问题描述
我正在尝试对使用com.basho.riak:riak-client:2.0.0的代码进行单元测试.我嘲笑了所有riak客户类,并希望得到一个无用但有效的测试.但是,此操作失败,并带有空指针:
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)
我的测试如下:
@Test public void test() {
RiakClient riakClient = mock(RiakClient.class);
@SuppressWarnings("unchecked")
RiakCommand<FetchValue.Response, Location> riakCommand = (RiakCommand<FetchValue.Response, Location>) 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
}
如何对使用riak客户端的测试代码进行单元化?最终,我想确保使用了预期的类型/存储桶/键组合,并确保了预期的RiakCommand运行了.
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.
我进一步研究了FetchValue类,并发现了以下结构:FetchValue
-是public final
I dug more into the FetchValue class and found this structure:FetchValue
- is public final
FetchValue.Response
-是public static
,
-具有程序包专用的构造函数Response(Init<?> builder)
FetchValue.Response
- is public static
,
- has a package-private constructor Response(Init<?> builder)
FetchValue.Response.Init<T>
是:
-protected static abstract class Init<T extends Init<T>> extends KvResponseBase.Init<T>
有FetchValue.Response.Builder
:static class Builder extends Init<Builder>
-使用build()表示:return new Response(this);
And there is FetchValue.Response.Builder
:static class Builder extends Init<Builder>
- with build() that: return new Response(this);
我假设Mockito在内部类中的某个地方迷路了,而我的呼叫最终在KvResponseBase.convertValues
中抛出了NP. KvResponseBase.convertValues
假定值是List<RiakObject>
,我看不到分配它的明智方法.
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<RiakObject>
of values and I see no sane way of assigning it.
推荐答案
我对您的情况进行了调查.我将您的示例简化为这个简单的SSCCE:
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());
}
}
会引发此错误:
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> T getValue(Class<T> clazz) {
}
}
似乎Mockito无法对该方法进行存根,因此调用了真正的方法,并抛出了NullPointerException
(由于访问了空成员:values
).需要注意的重要一件事是,如果此函数调用未失败,则Mockito将显示适当的错误:
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.
我想这是Mockito的错误或局限性,所以我在 Mockito跟踪器中打开了一个问题/a>我用简单的课程重述了你的情况.
我打开的问题实际上是已存在的.此问题不会得到解决,但是存在解决方法.您可以使用 Bytebuddy
模拟程序代替cglib模拟程序.在这里可以找到说明.
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.
这篇关于如何模拟riak Java客户端?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!