如何使用Mockito在Jetty中模拟继承的方法,而不是获取空指针异常

时间:2018-12-01 21:52:17

标签: java unit-testing mocking mockito embedded-jetty

这是源代码:

import org.eclipse.jetty.server.Server;

public class WebServer {

    private final Server server;

    public WebServer(Server server) {
        this.server = server;
    }

    public WebServer() {
        this(new Server(1234));
    }

    public void start() {
        try {
            server.start();
        } catch (Exception e) {
            throw new IllegalStateException(format("Could not start server on port '%d'", server.getURI().getPort()), e);
        }
    }

    public void stop() {
        try {
            server.stop();
        } catch (Exception e) {
            throw new IllegalStateException(format("Could not stop server on port '%d'", server.getURI().getPort()), e);
        }
    }
}

测试代码:

import org.eclipse.jetty.server.Server;

public class WebServerTest implements WithAssertions {

    private final Server server = mock(Server.class);
    private final WebServer webServer = new WebServer(server);

    @Test
    public void shouldStartJettyServer() throws Exception {
        webServer.start();

        verify(server).start();
    }
}

我想测试类WebServer,并确保它从服务器依赖项(来自Jetty库)中调用方法start()。源代码可以正常工作,并且测试很简单,应该只检查该模拟方法是否已调用。

但是当我碰到“ server.start()”时,我又重新获得了java.lang.NullPointerException。

看看jetty的源代码,start()方法是最终的,引发异常,并来自“服务器”类继承的父类“ AbstractLifeCycle”。

我想念什么?我怎样才能使该测试正常工作?是由于Server.start()引发了异常吗?与验证继承的方法有关(尽管我使用一些虚拟类进行了尝试,但这不是问题)?

我已经完成了相同的代码,但是我没有使用Jetty,而是使用了一个接口,并且测试通过了。

public class WebServer {

    private final Server server;

    public WebServer(Server server) {
        this.server = server;
    }

    public void startServer() {
        try {
            this.server.start();
        } catch (Exception e) {
            throw new IllegalStateException(format("Could not startServer server on port '%d'", this.server.getURI().getPort()), e);
        }
    }
}

和界面

public interface Server {
    void start();
    DatagramSocket getURI();
}

和测试代码

public class WebServerTest {

private final Server server = mock(Server.class);
private final WebServer webServer = new WebServer(server);

@Test
public void blah() throws Exception {
    webServer.startServer();

    verify(server).start();
}
}

因此,感觉就像码头如何实现start()和/或Mockito模拟Server类的内部

堆栈跟踪为

java.lang.NullPointerException     在org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:61)     在com.hanfak.greedydb.infrastructure.entrypoints.rest.JettyWebServerTest.shouldStartJettyServer(JettyWebServerTest.java:57)处     在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处     在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)     在java.lang.reflect.Method.invoke(Method.java:498)     在org.junit.runners.model.FrameworkMethod $ 1.runReflectiveCall(FrameworkMethod.java:50)     在org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)     在org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)     在org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)     在org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)     在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)     在org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)     在org.junit.runners.ParentRunner $ 3.run(ParentRunner.java:290)     在org.junit.runners.ParentRunner $ 1.schedule(ParentRunner.java:71)     在org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)     在org.junit.runners.ParentRunner.access $ 000(ParentRunner.java:58)     在org.junit.runners.ParentRunner上$ 2.evaluate(ParentRunner.java:268)     在org.junit.runners.ParentRunner.run(ParentRunner.java:363)     在org.junit.runner.JUnitCore.run(JUnitCore.java:137)     在com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)     在com.intellij.rt.execution.junit.IdeaTestRunner $ Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)     在com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)     在com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

2 个答案:

答案 0 :(得分:0)

此问题的根本原因似乎是Jetty的日志记录输出包含server.getURI().getPort()。您的模拟游戏会将null返回您尚未设置要返回的所有内容。如果您在测试设置中添加了when(server.getURI()).thenReturn(someUri),则可能会开始起作用。

答案 1 :(得分:0)

经过调查。我发现Jetty Server类从AbstractLifeCycle类继承了start()方法。此启动方法被声明为final。因此,mockito无法嘲笑这一点。

我发现使用此版本的Mockito(即Mocktio 2),请参见下面的Maven导入

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-inline</artifactId>
  <version>2.23.4</version>
  <scope>test</scope>
</dependency>

我现在可以运行测试,它将模拟它,并且上面的测试将通过。

以下是该库的文档:https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2#unmockable

课程:声明为final的任何方法或类都无法模拟。