Java: модульный тест лямбда-выражения внутри диспетчера - PullRequest
0 голосов
/ 24 сентября 2019

У меня есть класс:

public class RequestHandler implements HttpHandler {
  public void handleRequest(HttpServerExchange serverContext) throws Exception {
    serverContext.dispatch(() -> serverContext.getRequestReceiver()
        .receiveFullBytes((httpServerExchange, reqBytes) -> {

          // business logic along with few function call

        }
      )
    );

  }
} 

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

Я знаю, что мы можем переместить бизнес-логику в новый класс и можем ее протестировать (я думаю, она лучше разработана), но любопытно узнать, что, если это часть некоторыхустаревший код или что-то, что мы не можем изменить, как мы можем его протестировать?

1 Ответ

0 голосов
/ 25 сентября 2019

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

Обратите внимание, что HttpServerExchange - этопоследний класс, поэтому вам нужно использовать версию Mockito, которая поддерживает final mocking - и вы должны включить ее, как описано here.

Чтобы обойти лямбда-выражениевам нужно использовать thenAnswer или doAnswer для ручного вызова правильного метода интерфейса.

Простой пример может выглядеть следующим образом:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.stubbing.Answer;

import io.undertow.io.Receiver;
import io.undertow.io.Receiver.FullBytesCallback;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;

@ExtendWith(MockitoExtension.class)
public class RequestHandlerTest {

    static class BuisnessLogic {
        public void someMethod(HttpServerExchange httpServerExchange, byte[] reqBytes) {
        }
    }

    static class RequestHandler implements HttpHandler {

        BuisnessLogic logic;

        public void handleRequest(HttpServerExchange serverContext) throws Exception {
            serverContext.dispatch(
                () -> serverContext.getRequestReceiver().receiveFullBytes(
                    (httpServerExchange, reqBytes) -> {
                        logic.someMethod(httpServerExchange, reqBytes);
                    }
                )
            );
        }
    }

    @Mock
    BuisnessLogic logic;

    @InjectMocks
    RequestHandler handler;

    @Test
    public void test() throws Exception {

        byte[] message = new byte[] {1,2,3};
        HttpServerExchange serverContext = Mockito.mock(HttpServerExchange.class);

        // 1st lambda
        Mockito.when(serverContext.dispatch(Mockito.any(Runnable.class)))
               .thenAnswer((Answer<HttpServerExchange>) invocation -> {

            Runnable runnable = invocation.getArgument(0);
            runnable.run();

            return serverContext;
        });

        // 2nd lambda
        Receiver receiver = Mockito.mock(Receiver.class);
        Mockito.doAnswer((Answer<Void>) invocation -> {

            FullBytesCallback callback = invocation.getArgument(0);
            callback.handle(serverContext, message);

            return null;

        }).when(receiver).receiveFullBytes(Mockito.any(FullBytesCallback.class));

        Mockito.when(serverContext.getRequestReceiver()).thenReturn(receiver);

        // class under test - method invocation
        handler.handleRequest(serverContext);

        // buisness logic call verification
        ArgumentCaptor<HttpServerExchange> captor1 = ArgumentCaptor.forClass(HttpServerExchange.class);
        ArgumentCaptor<byte[]> captor2 = ArgumentCaptor.forClass(byte[].class);

        Mockito.verify(logic).someMethod(captor1.capture(), captor2.capture());

        Assertions.assertEquals(serverContext, captor1.getValue());
        Assertions.assertEquals(message, captor2.getValue());
    }
}

Как уже упоминалось, вы должны использовать этот подход только для устаревшего кода.

Простой рефакторинг может просто подтолкнуть всю деталь, которую нужно протестировать, к своему собственному методу, который - в приведенном выше примере - будет просто самой логикой бизнеса.

Нет явной необходимости тестировать фреймворк undertow самостоятельно.

...