I'm using Spring Boot to create a REST API and write some unit tests on my controllers.
I know that the recommended manner to inject beans in spring is the constructor injection.
But when i add the @SpringBootTest
annotation to my test class, I can not inject my controller class with constructor, I find myself obliged to use @Autowired
.
Have some explanation and is there another way to use constructor injection with SpringBootTest
.
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class PersonControllerTest {
@LocalServerPort
private int port;
@Autowired
private PersonController controller;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void greetingShouldReturnDefaultMessage() throws Exception {
assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/cvtech/Persons/",
String.class)).contains("content");
}
@Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
@Test
void findAllByJob() {
}
}
It's fine for your test to use field injection as the Test itself is not part of your domain; the test won't be part of your application context.
Also
You don't want to use SpringBootTest
to test a controller, because that will wire ALL beans which can be way too heavy and time-consuming. Instead, you probably only want to create your controller and it's dependencies.
So your best option is to use @WebMvcTest
which will only create the beans required for testing the specified controller.
@ExtendWith(SpringExtension.class)
@WebMvcTest(controllers = PersonController.class)
class PersonControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void greetingShouldReturnDefaultMessage() throws Exception {
mockMvc.perform(get("/cvtech/Persons"))
.andExpect(status().isOk())
.andExpect(content().string(contains("content")));
}
}
Note that @WebMvcTest
will search for a class annotated with @SpringBootConfiguration
as it's default configuration. If it does not find it, or you want to manually specify some configuration classes, also annotate the test with @ContextConfiguration
.
Also, as a sidenote, when using TestRestTemplate
, you don't need to specify host and port. Just call restTemplate.getForObject("/cvtech/persons", String.class));
Same when using MockMvc
or WebTestClient
.