2

Spring Boot here. I currently have the following REST controller:

@RestController
public class FizzbuzzController {

    private final FizzbuzzService FizzbuzzService;

    public FizzbuzzController(FizzbuzzService FizzbuzzService) {
        this.FizzbuzzService = FizzbuzzService;
    }

    @PostMapping("/Fizzbuzzs/{fizzbuzzId}")
    public ResponseEntity<FizzbuzzDTO> addFizzbuzz(@RequestParam("files") List<MultipartFile> files,
                                      @PathVariable String fizzbuzzId) throws IOException {

        FizzbuzzDTO fizzbuzzDTO = fizzbuzzService.store(files, fizzbuzzId);
        return ResponseEntity.status(HttpStatus.OK).body(fizzbuzzDTO);
        
    }

}

I would like to write an integration test for it that:

  1. Mocks or stubs an HTTP request to the URL; and
  2. Allows me to inject the FizzbuzzController (under test) with a mocked FizzbuzzService or the real thing; and
  3. Allows me to inspect the HTTP response coming back from the method (check status code, check response entity, etc.)

My best attempt thus far:

@WebMvcTest(FizzbuzzController.class)
@EnableConfigurationProperties
@AutoConfigureMockMvc
public class FizzbuzzControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private FizzbuzzService FizzbuzzService;

    @Test
    public void should_store_fizzbuzz_files() throws Exception {
        // I can't even get the test to run
        assertTrue(1 == 1);
    }

}

When I run this, the test fails to run and it is clear (looking at the logs) that Spring is loading the entire application context of my app, whereas I just want it to isolate the context to this test class, the main FizzbuzzController class, and anything in the dependency tree underneath it.

Can anyone spot where I'm going awry?

2 Answers 2

2

You need another context for testing. I'm suggesting you to have a separate Test config:

@TestConfiguration
@Slf4j
@EnableJpaRepositories("tth.patientportal.repository")
public class TestConfig { // bean configs goes here for testing if you need to change 
  // context}

and in a controller test build the context like below:

@RunWith(SpringRunner.class)
@AutoConfigureTestEntityManager
@SpringBootTest
@TestPropertySource("classpath:application-unittest.properties")
@ContextConfiguration(classes = {TestConfig.class})    
public class RestControllerTest {
    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setup() 
    {
       mockMvc = MockMvcBuilders.
            webAppContextSetup(webApplicationContext)
            .build();
    }

    @Test
    public void shouldReturnRegisteredUser() throws Exception {
        this.mockMvc.
            perform(MockMvcRequestBuilders
                    .post("url")                        
                    .contentType(MediaType.APPLICATION_JSON)
                    .accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(MockMvcResultMatchers.jsonPath("$.username").exists());
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much @Shamitha (+1) -- quick question, what does @EnableJpaRepositories("...") do?
That's for when you use jpa repositories, I bet you are going to need them
0

You don't need separate @TestConfiguration to perform integration tests using @WebMvcTest, @RestClientTest or other dedicated annotations, that load only subset of beans from your entire application. But you must be aware, that the way you configure your application may disrupt beans filtering and you will end up with your case of "Spring is loading the entire application context of my app".

See this quote from "Testing Spring Boot Applications" documentation:

If you use a test annotation to test a more specific slice of your application, you should avoid adding configuration settings that are specific to a particular area on the main method’s application class.

The underlying component scan configuration of @SpringBootApplication defines exclude filters that are used to make sure slicing works as expected. If you are using an explicit @ComponentScan directive on your @SpringBootApplication-annotated class, be aware that those filters will be disabled. If you are using slicing, you should define them again.

In my case, I fixed this issue by simple moving all @Enable... and @ComponentScan custom annotations away from @SpringBootApplication, to separate @Configuration class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.