How to mock an Elasticsearch Java Client? How to mock an Elasticsearch Java Client? elasticsearch elasticsearch

How to mock an Elasticsearch Java Client?


I've come across a similar problem when mocking builders, so I thought I'd experiment to see if there is a nicer way.

As Mr Spoon said, it's probably nicer if you can avoid doing do this in the first place as it is not your code and could be assumed to "just work", but I thought I'd give it a go anyway.

I've come up with a (maybe crude) way of doing it by using "default answers" in Mockito. I'm still deciding if I like it or not.

Here's my builder...

public class MyBuilder {    private StringBuilder my;    public MyBuilder() {        my = new StringBuilder();    }    public MyBuilder name(String name) {        my.append("[name=").append(name).append("]");        return this;    }    public MyBuilder age(String age) {        my.append("[age=").append(age).append("]");        return this;    }    public String create() {        return my.toString();    }}

(Pretty basic right?)

I got my test to look something like this...

// Create a "BuilderMocker" (any better name suggestions welcome!) BuilderMocker<MyBuilder> mocker = BuilderMocker.forClass(MyBuilder.class);// Get the actual mock builderMyBuilder builder = mocker.build();// expect this chain of method calls...mocker.expect().name("[NAME]").age("[AGE]");// expect this end-of-chain method call...Mockito.when(builder.create()).thenReturn("[ARGH!]");

Now if I do the following...

System.out.println(builder.name("[NAME]").age("[AGE]").create());

...I expect "[ARGH!]" to be output.

If I altered the last line...

System.out.println(builder.name("[NOT THIS NAME]").age("[AGE]").create());

...then I expect it to break with a NullPointerException.

Here is the actual "BuilderMocker"...

import static org.mockito.Mockito.mock;import static org.mockito.Mockito.when;import static org.mockito.Mockito.withSettings;import org.mockito.invocation.InvocationOnMock;import org.mockito.stubbing.Answer;public class BuilderMocker<T> {    private Class<T> clazz;    private T recorder;    private T mock;    // Create a BuilderMocker for the class    public static <T> BuilderMocker<T> forClass(Class<T> clazz) {        return new BuilderMocker<T>(clazz);    }    private BuilderMocker(Class<T> clazz) {        this.clazz = clazz;        this.mock = mock(clazz);        createRecorder();    }    // Sets up the "recorder"    private void createRecorder() {        recorder = mock(clazz, withSettings().defaultAnswer(new Answer<Object>() {            @Override            public Object answer(InvocationOnMock invocation) throws Throwable {                // If it is a chained method...                if (invocation.getMethod().getReturnType().equals(clazz)) {                    // Set expectation on the "real" mock...                    when(invocation.getMethod().invoke(mock, invocation.getArguments())).thenReturn(mock);                    return recorder;                }                return null;            }        }));    }    // Use this to "record" the expected method chain    public T expect() {        return recorder;    }    // Use this to get the "real" mock...    public T build() {        return mock;    }}

Not sure if there is a "built-in" way of doing this in Mockito, but this seems to work.