Home > Back-end >  Spring Testing MVC: In controller under test, mocked service returned value not getting set as a JSO
Spring Testing MVC: In controller under test, mocked service returned value not getting set as a JSO

Time:11-08

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)

CodePudding user response:

As you are using Async coding (and not full webflux) you need to do that with MockMvc as well. The javadoc of the MockMvcRequestBuilders has an example of such a thing. Applying that to your code would make it something like this.

@Test
void testGetCustomerOTCBalance() throws Exception {

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

    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/customer/otc-balance").accept(MediaType.APPLICATION_JSON);
    MvcResult result = mvc.perform(requestBuilder).andExpect(request().asyncStarted())
        .andReturn();
    mvc.perform(asyncDispatch(result))
         .andExpect(MockMvcResultMatchers.jsonPath("$.otcBalance").value(1.30));
}

Something along those lines.

CodePudding user response:

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.

  • Related