mockito和jetty-client:调用start()和stop()方法时接收NullPointerException

时间:2014-08-05 22:52:44

标签: java testing mocking jetty mockito

我正在测试这段代码

  this.httpClient.start();
  ContentResponse response = this.httpClient.newRequest(Protocol.IMAGES())
                                            .method(HttpMethod.GET)
                                            .send();

  if(response.getStatus() != 200)
    throw new HostIsNotReachableException();

  images = ImageList.fromJson(response.getContentAsString());

  this.httpClient.stop();
使用

HttpClient httpClient = mock(HttpClient.class);
Request request = mock(Request.class);
ContentResponse response = mock(ContentResponse.class);
when(httpClient.newRequest(Protocol.IMAGES())).thenReturn(request);
when(request.method(HttpMethod.GET)).thenReturn(request);
when(request.send()).thenReturn(response);
when(response.getStatus()).thenReturn(200);
when(response.getContentAsString()).thenReturn(gson.toJson(images));
...
verify(httpClient, times(1)).start();
verify(httpClient, times(1)).stop();
verify(httpClient, times(1)).newRequest(Protocol.IMAGES());
verify(request, times(1)).method(HttpMethod.GET);
verify(request, times(1)).send();

当调用start()和/或stop()方法时,测试会报告意外的NullPointerException。模拟定义中有一些我想念的东西吗?

这是例外的日志:

java.lang.NullPointerException
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:61)
at com.meetecho.docker.client.ClientTest.itShouldGetTheImagesList(ClientTest.java:99)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)

4 个答案:

答案 0 :(得分:2)

很好的问题,我遇到了一个非常类似的问题,这个stackoverflow出现在谷歌搜索结果的顶部。

在我的情况下,我试图测试一个代码片段,它将我的自定义Filter添加到我的ApplicationContext中,在必要时模拟对象。我遇到的问题是,当我的代码名为filterHolder.start()时(实际上是AbstractLifeCycle中的最终方法start()),它会抛出NullPointerException。

进一步建立自己的自我答案:你可以使用Powermock来解决Mockito无法模拟最终方法的问题。

使用项目中包含的Powermock库,启用Powermock运行器并标记AbstractLifeCycle.class类以进行字节码操作:

@PrepareForTest(AbstractLifeCycle.class)
@RunWith(PowerMockRunner.class)
public class MyTestClass extends Assert {

然后,模拟出initialize()和start()方法:

doAnswer(new DoesNothing()).when(holder).initialize();
doAnswer(new DoesNothing()).when(holder).start();

它应该可以正常工作。

答案 1 :(得分:1)

我自动回复我的回答,因为没有人提出正确的解决方案。

我意识到jetty-client类的启动/停止方法是最终的。 Mockito不会模拟最终方法,而是执行它们的实际实现。

我现在如何解决这个问题?开始使用jersey-client。

答案 2 :(得分:0)

对象 httpClient 看起来像是null。您实际上是在模拟httpClient,但在您正在测试的实际代码中从未收到模拟。

即使您注入了对象,或者您正在实例化它在测试代码中执行新的HttpClient,您也必须添加一个setter方法才能从外部设置httpClient对象。当然,这种方法仅用于测试目的,但这是一种常见的做法。

换句话说,假设您的代码在A类中,并且包含要作为testes的代码的方法是methodA的方法,您应该有类似于:

class A {
    private HttpClient httpClient=null; 

    public methodA {
        if (this.httpClient==null) this.httpClient = new HttpClient(...);
        <YOUR CODE>
    }

    public void setHttpClient(HttpClient httpClient) {
        this.httpClient = httpClient;
    }
    ...
 }

在测试中你应该调用方法 setHttpClient 作为参数传递你在第一行创建的HttpClient的模拟。

答案 3 :(得分:0)

在较新的Mockito版本中,您可以按照https://www.baeldung.com/mockito-final中的建议执行以下操作:

在Mockito可用于模拟最终类和方法之前,它 需要配置。

我们需要将文本文件添加到项目的 src / test / resources / mockito-extensions目录名为 org.mockito.plugins.MockMaker并添加一行文本:

mock-maker-inline

Mockito检查扩展目录是否存在 加载时的配置文件。该文件启用模拟 最后的方法和类。