Как смоделировать унаследованный метод в Jetty, используя mockito, вместо получения исключения нулевого указателя - PullRequest
0 голосов
/ 02 декабря 2018

Вот исходный код:

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 и убедиться, что он вызывает метод start () изЗависимость от сервера (из библиотеки Jetty).Исходный код работает, и тест прост и должен просто проверить, что метод на макете вызывается.

Но тогда я получаю обратно java.lang.NullPointerException, когда он обращается к "server.start ()".

Глядя на исходный код Jetty, метод start () является окончательным,выдает исключение и приходит из родительского класса "AbstractLifeCycle", который наследуется классом "Server".

Что мне не хватает?Как я могу заставить этот тест работать?Это связано с тем, что 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();
}
}

Таким образом, вы чувствуете, что что-то внутреннее в том, как Jetty реализует start () и / или как mockito издевается над классом Server

Трассировка стека

java.lang.NullPointerException at org.eclipse.jetty.util.component.AbstractLifeCycle.start (AbstractLifeCycle.java:61) в com.hanfak.greedydb.infrastructure.entrypoints.rest.JettyWebServerTest.shouldSter57sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) в sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) в sun.reflect.DelegatingMethodAccessorImpl.indho.j.fho.j.jav.jjinvoke (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.InvoeMeho (17) в org.junit.runners.ParentRunner.runLeaf (ParentRunner.java:325) в org.junit.runners.BlockJUnit4ClassRunner.runChild (BlockJUnit4ClassRunner.java:78) в org.junlassRunn.unjun4: 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.оценке (ParentRunner.java:268) в org.junit.runners.Parent.run (ParentRunner.java:363) в org.junit.runner.JUnitCore.run (JUnitCore.java:137) в com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs (JUnit4Iunerjest)a: 68) в com.intellij.rt.execution.junit.IdeaTestRunner $ Repeater.startRunnerWithArgs (IdeaTestRunner.java:47) в com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAnditS2.intellij.rt.execution.junit.JUnitStarter.main (JUnitStarter.java:70)

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

После расследования.Я обнаружил, что класс Jetty Server наследует метод start () от класса AbstractLifeCycle.Этот метод запуска объявлен окончательным.Таким образом, мокито не может издеваться над этим.

Я обнаружил, что используя эту версию mockito (т.е. mocktio 2), см. Ниже для maven import

<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, не может быть смоделирован.

0 голосов
/ 03 декабря 2018

Основная причина этого может заключаться в том, что выходные данные журнала Jetty включают server.getURI().getPort().Ваш макет вернет null всему, что вы не настроили для возврата.Если вы добавите when(server.getURI()).thenReturn(someUri) в тестовую настройку, это, вероятно, начнет работать.

...