riak教程 java,如何模拟riak Java客户端?

2022-05-24 00:00:00 专区 订阅 付费 交易 评论

I'm trying to unit test code that uses com.basho.riak:riak-client:2.0.0. I mocked all riak client classes and was hoping to get a useless but working test. However, this fails with a null pointer:

java.lang.NullPointerException

at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243)

at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150)

at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171)

My test looks like this:

@Test public void test() {

RiakClient riakClient = mock(RiakClient.class);

@SuppressWarnings("unchecked")

RiakCommand riakCommand = (RiakCommand) mock(RiakCommand.class);

Response response = mock(Response.class);

when(riakClient.execute(riakCommand)).thenReturn(response);

Response returnedResponse = riakClient.execute(riakCommand);

when(response.getValue(Object.class)).thenReturn(new Object());

MyPojo myData = returnedResponse.getValue(MyPojo.class);

// Make assertions

}

How do you unit test code that uses the riak client? Eventually I would like to ensure that the expected type/bucket/key combination is used and that the expected RiakCommand is run.

EDIT: I dug more into the FetchValue class and found this structure:

FetchValue

- is public final

FetchValue.Response

- is public static,

- has a package-private constructor Response(Init> builder)

FetchValue.Response.Init is:

- protected static abstract class Init> extends KvResponseBase.Init

And there is FetchValue.Response.Builder:

static class Builder extends Init

- with build() that: return new Response(this);

I assume that Mockito gets lost somewhere among the inner classes and my call ends up in KvResponseBase.convertValues, where the NP is thrown. KvResponseBase.convertValues assumes a List of values and I see no sane way of assigning it.

解决方案

I have investigate a bit your case. I have reduce your example to this simple SSCCE:

import static org.mockito.BDDMockito.given;

import static org.mockito.Mockito.mock;

import org.junit.Test;

import com.basho.riak.client.api.commands.kv.FetchValue.Response;

public class RiakTest {

@Test

public void test() throws Exception {

Response response = mock(Response.class);

given(response.getValue(Object.class)).willReturn(new Object());

}

}

which throws this error:

java.lang.NullPointerException

at com.basho.riak.client.api.commands.kv.KvResponseBase.convertValues(KvResponseBase.java:243)

at com.basho.riak.client.api.commands.kv.KvResponseBase.getValue(KvResponseBase.java:150)

at com.basho.riak.client.api.commands.kv.FetchValue$Response.getValue(FetchValue.java:171)

at RiakTest.test(RiakTest.java:12)

After some digging, i think i have identified the problem. It is that you are trying to stub a public method which is inherited from a package (visibility) class:

abstract class KvResponseBase {

public T getValue(Class clazz) {

}

}

It seems that Mockito fails to stub this method so the real one is invoked and a NullPointerException is thrown (due to an access of a null member: values).

One important thing to note is that if this function invocation not fails, Mockito would show a proper error:

org.mockito.exceptions.misusing.MissingMethodInvocationException:

when() requires an argument which has to be 'a method call on a mock'.

For example:

when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:

1. you stub either of: final/private/equals()/hashCode() methods.

Those methods *cannot* be stubbed/verified.

Mocking methods declared on non-public parent classes is not supported.

2. inside when() you don't call method on mock but on some other object.

I guess it is a Mockito bug or limitation so i have open an issue in the Mockito tracker where i have reproduce your case with simple classes.

UPDATE

The issue i opened is in fact a duplicate of an existing one. This issue will not be fixed but a workaround exists. You may use the Bytebuddy mockmaker instead of the cglib one. Explanations could be found here.

相关文章