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

问题描述 投票:3回答:4

我正在测试此代码段

  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)
java testing mocking jetty mockito
4个回答
2
投票

最大的问题,我遇到了一个非常相似的问题,这个stackoverflow对我来说出现在Google搜索结果的顶部。

就我而言,我正在尝试测试将我的自定义过滤器添加到我的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
投票

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

我意识到码头客户端类的启动/停止方法是最终的。Mockito不模拟最终方法,而是执行其实际实现。

我现在如何解决此问题?通过开始使用jersey-client。


0
投票

看起来对象httpClient为空。您实际上是在模拟httpClient,但从未在要测试的实际代码中收到该模拟。

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

换句话说,假设您的代码在A类中,并且包含要测试的代码的方法是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的模拟作为参数传递。


0
投票

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

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

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

mock-maker-inline

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

© www.soinside.com 2019 - 2024. All rights reserved.