Mockito: Это плохая практика, чтобы шпионить за методом в тестируемой системе, который опирается на HTTP-запрос? - PullRequest
0 голосов
/ 07 декабря 2018

Из-за прочтения, это обычно плохая практика и признак запаха кода, когда вы должны следить за методом, который используется текущим методом, который вы тестируете модулем.

Например, у меня естьэтот метод, который я тестирую модулем:

public MyResponseObject doStuff(MyRequestObject obj) {
    WebTarget tar = getServiceClient().target(obj.toString());
    Response res = tar.path(someURI).request().post(somejson);
    if(response.getStatus() == 200) {
        String jsonResp = response.readEntity(String.class);
        return convertToObj(jsonResp);
    }
}

Один из способов, которым я пытаюсь решить вышеизложенное, -

  1. Извлечение первых двух строк (WebTarget, Response) всвой собственный метод, который возвращает объект Response.
  2. Создание макета Response и создание заглушки readEntity для возврата 200 и readEntity для возврата "OK"

Вот результат:

public MyResponseObject doStuff(MyRequestObject obj) {
    Response res = sendRequest(obj.toString());
    if(response.getStatus() == 200) {
        String jsonResp = response.readEntity(String.class);
        return convertToObj(jsonResp);
    }
}

//extracted method
public Response sendRequest(String json){
    WebTarget tar = getServiceClient().target(someUrl);
    return res = tar.path(someURI).request().post(somejson);
}

//My unit test

//sut is the system under test, setup elsewhere
public void testDoStuff() {
    MyRequestObject request = ...;
    Response respMock = mock(Response.class);
    when(respMock.getStatus()).thenReturn(200);
    when(respoMock.readEntity()).thenReturn("OK");
    MyClass spy = spy(sut);
    Mockito.doReturn(respMock).when(spy).sendRequest(requestString);
    MyResponseObject  response = spy.doStuff(request);

    assertEquals(response.toString(),expectedResp);
}

Если я не заглушу это, он пытается выполнить реальный HTTP-запрос и возвращает недопустимую ошибку URL-адреса, потому что я не предоставляю реальный - я считаю, что это то, что я хочу, потому что я хочу свои модульные тестыбыть независимым от какой-то внешней системы.

Есть ли лучший способ, которым я должен заниматься своим модульным тестированием?

Ответы [ 2 ]

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

Шпионаж объекта, который вы тестируете, считается мне плохой практикой, но эти предупреждения не приводят никаких объяснений, подтверждающих его.Я уверен, что, как и все остальное, им определенно можно злоупотреблять.

Что я заметил при тестировании метода, вызывающего другой метод тестируемого объекта, то лучше, если вы сможете отключить тестированиеоба метода одновременно.Несмотря на то, что вы можете издеваться над вторым методом, чтобы упростить тестирование первого метода, вам все равно придется вернуться в какой-то момент и протестировать второй метод.Лично я поддерживаю насмешку над вторым методом, если он приводит к более чистому тестовому коду.По сути, это вариант, который вам дает вселенная, и его нельзя исключать для всех случаев.

В вашем сценарии я бы предпочел высмеивать объект WebTarget вместо создания второго внутреннего метода.,Основная причина этого заключается в том, что вам все равно придется вернуться и протестировать второй метод, так что, возможно, стоит заняться им сейчас.Но если вы обнаружите, что ваш код может быть чище, разделив эти первые две строки на их собственный метод (или класс), потому что это повторно используемый код, который используется многократно, то, конечно, разделите его на свой собственный метод.В этом случае архитектура самого кода (а не требований к тестированию) диктует структуру кода.

При издевательстве над WebTarget, в данном случае это связано с работой с методами компоновщика, например.path(someURI).request().post(somejson), каждый из которых должен быть высмеян соответственно.Так что это немного больно.Если бы я делал это, я бы, возможно, использовал интеграционное тестирование вместо юнит-тестирования.Другими словами, подключите и установите сервер, чтобы я мог проверить его.В нашей тестовой среде все серверы остаются работоспособными, поэтому мы можем использовать больше интеграционных тестов по сравнению с юнит-тестами.По мере роста среды это может оказаться невозможным, но сейчас это так и ведет к более чистым интеграционным тестам, которые выбивают большую часть кода при меньшем количестве тестов.

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

Да, создание шпиона класса, который вы тестируете, является плохой практикой, разбивать код, который вы копируете, на другой класс и имитировать это, то есть:

public class MyClass {

    private final MySender sender;

    public MyClass() {
        this(new DefaultSender());
    }

    public MyClass(MySender sender) {
        this.sender = sender;
    }

    public MyResponseObject doStuff(MyRequestObject obj) {
        Response res = sender.sendRequest(obj.toString());
        if (response.getStatus() == 200) {
            String jsonResp = response.readEntity(String.class);
            return convertToObj(jsonResp);
        }
    }

    public interface MySender {
        Response sendRequest(String json);
    }

    private static class DefaultSender implements MySender {
        public Response sendRequest(String json) {
            WebTarget tar = getServiceClient().target(someUrl);
            return res = tar.path(someURI).request().post(somejson);
        }
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    private MyClass testSubject;

    @Mock
    private MySender sender;

    @Mock
    private Response response;

    @Test
    public void testDoStuff() {
        String expectedResp = ...;
        MyRequestObject request = ...;
        MyResponseObject  response = testSubject.doStuff(request);

        assertEquals(response.toString(),expectedResp);
    }

    @Before
    public void setup() {
        testSubject = new MyClass(sender);
        when(sender.sendRequest(anyString()).thenReturn(response);
        when(response.getStatus()).thenReturn(200);
        when(response.readEntity()).thenReturn("OK");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...