Search code examples
javaintegration-testingjunit4spring-webflux

Spring boot intergration test returns empty result


I am trying to make intergration tests for my webflux controller, but the test are failing either on not set content-type or on empty content. Controller class:

@RestController
@RequiredArgsConstructor
@SecurityRequirement(name = "bearerAuth")
@Log4j2
public class OnboardingController {
    private final Service service;

    @GetMapping(value = "/organizationQuotas", produces = MediaType.APPLICATION_JSON_VALUE)
    public Flux<OrganizationQuota> getOrganizationQuotas() {
        return service.getAllOrganizationQuotas();
    }
}

Service class is a simple flux-returning service. Test class:

@WebMvcTest(OnboardingController.class)
@RunWith(SpringRunner.class)
public class OnboardingControllerIT {

    @MockBean
    Service service;
    private EasyRandom easyRandom = new EasyRandom();

    @Autowired
    private MockMvc mockMvc;

    @Test
    @WithMockUser(authorities = {"..."})
    @DisplayName("Should List All organization quotas when GET request to /organizationQuotas")
    public void shouldReturnOrganizationQuotas() throws Exception {
        when(service.getAllOrganizationQuotas())
                .thenReturn(Flux.fromStream(easyRandom.objects(OrganizationQuota.class, 5)));

        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/organizationQuotas").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
//                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$.*", isA(ArrayList.class)))
                .andReturn();
    }
}

At this state the output looks like this:

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /organizationQuotas
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json"]
             Body = null
    Session Attrs = {SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@d1e9b4bb: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@d1e9b4bb:...}

Handler:
             Type = controller.OnboardingController
           Method = controller.OnboardingController#getOrganizationQuotas()

Async:
    Async started = true
     Async result = [OrganizationQuota{allowPaidServicePlans=true, ...}]

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

and it ends with exception

No value at JSON path "$.*"
java.lang.AssertionError: No value at JSON path "$.*"
...

I have these dependencies

    testImplementation 'org.jeasy:easy-random-randomizers:5.0.0'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'

    testCompile 'io.projectreactor:reactor-test'

Security should work ok. I can see the async result that is correct but my matchers are not working with it. The content type is not returned as well. Is it because of the async character of request? How can I make it evaluate? Thanks for help.


Solution

  • I found it at howToDoInJava that testing async controller is different:

    I had to use asyncDispatch method. Form the referenced page, here is the example:

          @Test
          public void testHelloWorldController() throws Exception 
          {
                MvcResult mvcResult = mockMvc.perform(get("/testCompletableFuture"))
                                  .andExpect(request().asyncStarted())
                                  .andDo(MockMvcResultHandlers.log())
                                  .andReturn();
                 
                mockMvc.perform(asyncDispatch(mvcResult))
                            .andExpect(status().isOk())
                            .andExpect(content().contentTypeCompatibleWith("text/plain"))
                            .andExpect(content().string("Hello World !!"));
          }
    

    now it works correctly.