Search code examples
spring-mvcmockitointegration-testingspring-webfluxspring-test-mvc

Spring WebFlux: In controller under test, mocked service returned value not getting set as a JSON Response


Having a problem with my mocked return response from my controller.

The async response is returning as the actual POJO not the serialized json.

Running the application and using Postman, the returned response is indeed a JSON Object... but testing it returns the actual mock POJO I've created... here is my test case.

@WebMvcTest(CustomerController.class)
class CustomerControllerTest {
@Autowired
MockMvc mvc;

@MockBean
private CustomerService customerService;

private Mono<OtcBalanceResponse> responseMono;

private OtcBalanceResponse otcResponseMock;

@BeforeEach
void setupMocks() {
    OtcBalanceResponse otcResponseMock = new OtcBalanceResponse();
    otcResponseMock.setOtcBalance(new BigDecimal("1.30"));
    otcResponseMock.setUserId("testID");
    responseMono = Mono.just(otcResponseMock);
}
@Test
void testGetCustomerOTCBalance() throws Exception {

    when(customerService.getCustomerOTCBalance((OtcBalanceRequest) any()))
            .thenReturn(responseMono);

    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/customer/otc-balance").accept(MediaType.APPLICATION_JSON);

    mvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.jsonPath("$.otcBalance").value(1.30));
}

}

here is my Controller class

  @GetMapping("/otc-balance")
  public Mono<OtcBalanceResponse> getCustomerOTCBalance(OtcBalanceRequest otcBalanceRequest){
    return customerService.getCustomerOTCBalance(otcBalanceRequest);
}

Here is my service

    public Mono<OtcBalanceResponse> getCustomerOTCBalance(OtcBalanceRequest request) {

    return webClientBuilder
            .baseUrl(customerBase)
            .build()
            .post()
            .uri(otcBalancePath)
            .body(BodyInserters.fromValue(request))
            .retrieve()
            .bodyToMono(OtcBalanceResponse.class);
}

this is my logged result

Async:
Async started = true
 Async result = OtcBalanceResponse(otcBalance=1.30, otcRolloverFlag=false, isIncommMember=false, otcStartDate=null, otcEndDate=null)

Solution

  • You seem to be using webflux, the easiest path is to use webflux-specific classes:

    • WebFluxTest instead of WebMvcTest
    • WebTestClient instead of MockMvc
    @WebFluxTest(CustomerController.class)
    class CustomerControllerTest {
        @Autowired
        private WebTestClient webClient;
    
        // ...
    
        @Test
        void testGetCustomerOTCBalance() throws Exception {
    
            when(customerService.getCustomerOTCBalance(any()))
                    .thenReturn(responseMono);
    
            webClient.get().uri("/customer/otc-balance")
                    .exchange()
                    .expectStatus().isOk()
                    .expectBody()
                    .jsonPath("$.otcBalance").isEqualTo(1.30);
    
        }
    
    }
    

    Other remarks - you are not OtcBalanceRequest to the controller - but any() argument matcher accepts null. Using a eq argument matcher would make your test better - you would check that the request is correctly deserialized by the controller.