Mockito - Unmocked метод не смог вернуть сам объект - PullRequest
2 голосов
/ 21 апреля 2020

У меня есть Spring @RestController, у которого есть поле Apache Верблюжий интерфейс FluentProducerTemplate.

Я тестирую контроллер с MockMvc, и я вводю FluentProducerTemplate как ложный.

Я бы хотел высмеять только один метод - request() и использовать реальную реализацию других методов.

Однако я получаю NullPointerException от немодированных методов. Другие FluentProducerTemplate методы n имеют тип возврата FluentProducerTemplate. В реализации они возвращают this. Объект mock возвращает ноль.

  1. Я думал, что mockito @Mock высмеивает только те методы, которые я указал. Другие методы используют оригинальную реализацию. Это правильное утверждение?
  2. Я попытался @Spy вместо @Mock и получил ту же ошибку.
  3. Когда я высмеиваю все методы, с которыми я работаю, это работает, и нет NullPointerException.

Код:

REST Контроллер:

@RestController
@RequestMapping("/v1/test”)

public class MyController {


@EndpointInject(uri = "direct:main")
private FluentProducerTemplate producerTemplate;

@RequestMapping(value = “/test2”, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public MyResponse testRequest(
        @RequestHeader(“id”) String id,
        @RequestHeader(“context”) String context,
        @RequestBody RequestBody requestBody
) {
    MyResponse response = producerTemplate
            .withHeader(“id”, id)
            .withHeader(“context”, context)
            .withBody(requestBody)
            .request(MyResponse.class);
    return response;
}

Тест:

@RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {

    private MockMvc mockMvc;

    @Mock
    private FluentProducerTemplate producerTemplateMock;

    @InjectMocks
    private MyControllerTest myController;

    private static MyResponse expectedResultSuccess;

    private static String requestString;

    private static HttpHeaders allRequestHeaders;

    @BeforeClass
    public static void setup() {

        allRequestHeaders = new HttpHeaders();
        allRequestHeaders.set(“id”, “123”);
        allRequestHeaders.set(“context”, “ABCD1234”);
        allRequestHeaders.set(“Content-Type”, “application/json”);

        expectedResultSuccess =  new MyResponse(“test”);

        requestString = “request”BodyText;

    }

    @Before
    public void init() {

        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();

        when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);

    }

    @Test
    public void testSuccess() throws Exception {

        mockMvc.perform(post(“/v1/test/test2)
                .headers(allRequestHeaders)
                .content(requestString))
                .andExpect(status().isOk())

    }

}

Тест проходит только тогда, когда я добавляю ниже к init():

  when(producerTemplateMock.withHeader(any(), any())).thenReturn(producerTemplateMock);
  when(producerTemplateMock.withBody(any())).thenReturn(producerTemplateMock);

Мой главный вопрос - почему я должен издеваться над всеми методами? Я предпочитаю использовать оригинальную реализацию withHeader() и withBody() и только макет request().

1 Ответ

2 голосов
/ 21 апреля 2020

Вы хотите так называемые частичные насмешки. В зависимости от того, хотите ли вы установить в основном макеты или в основном вызывать реальные реализации, существуют разные предпочтительные подходы.

1. spy для нескольких макетов, в основном для реальной реализации

Если вы хотите смоделировать только некоторые методы и в противном случае вызвать реальную реализацию:

FluentProducerTemplate producerTemplateMock = spy(FluentProducerTemplate.class);

// Mock implementation
doReturn(expectedResultSuccess).when(producerTemplateMock).request(any());

// All other method call will use the real implementations

2. mock для в основном макетов, мало реальных реализаций

FluentProducerTemplate producerTemplateMock = mock(FluentProducerTemplate.class);

// Mock methods
when(producerTemplateMock.request(any())).thenReturn(expectedResultSuccess);

// tell mockito to call the real methods
when(producerTemplateMock.withHeader(any(), any())).thenCallRealMethod;
when(producerTemplateMock.withBody(any())).thenCallRealMethod();

Как видите, 2-й подход более шаблонен для написания. Однако, в зависимости от вашего варианта использования, какой подход лучше подходит.

...