142

I am new to Spring Boot and am trying to understand how testing works in SpringBoot. I am a bit confused about what is the difference between the following two code snippets:

Code snippet 1:

@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerApplicationTest {
    @Autowired    
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}

This test uses the @WebMvcTest annotation which I believe is for feature slice testing and only tests the MVC layer of a web application.

Code snippet 2:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
    mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}

This test uses the @SpringBootTest annotation and a MockMvc. So how is this different from code snippet 1? What does this do differently?

Edit: Adding Code Snippet 3 (Found this as an example of integration testing in the Spring documentation)

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
public class HelloControllerIT {
    
    @LocalServerPort private int port;
    private URL base;
    
    @Autowired private TestRestTemplate template;
    
    @Before public void setUp() throws Exception {
        this.base = new URL("http://localhost:" + port + "/");
    }
    
    @Test public void getHello() throws Exception {
        ResponseEntity < String > response = template.getForEntity(base.toString(), String.class);
        assertThat(response.getBody(), equalTo("Greetings from Spring Boot!"));
    }
}
Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Revansha
  • 1,923
  • 4
  • 16
  • 21

2 Answers2

131

@SpringBootTest is the general test annotation. If you're looking for something that does the same thing prior to 1.4, that's the one you should use. It does not use slicing at all which means it'll start your full application context and not customize component scanning at all.

@WebMvcTest is only going to scan the controller you've defined and the MVC infrastructure. That's it. So if your controller has some dependency to other beans from your service layer, the test won't start until you either load that config yourself or provide a mock for it. This is much faster as we only load a tiny portion of your app. This annotation uses slicing.

Reading the doc should probably help you as well.

buræquete
  • 14,226
  • 4
  • 44
  • 89
Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
  • Thanks a lot for responding !!. So if I understand you correctly, what that means is that both the code snippets test only the MVC part of the application. But tcode snippet 1 loads the full application context whereas code snippet 2 only scans the controller. Is this correct? Can the code snippet 1 be considered as a unit test to test the controller? – Revansha Oct 06 '16 at 04:13
  • 2
    No it's not correct. `SpringBootTest` is loading your full app (to some extend, by default it won't start the embedded container if there is one available, that's what the `webEnvironment` is there for). I wouldn't say that `@SpringBootTest` is a unit test of the controller but more an integration test, really. `WebMvcTest` is really a unit test of your controller in the sense that if it has dependency, you'll have to provide them yourself (either a config or a mock of some kind). – Stephane Nicoll Oct 06 '16 at 07:49
  • Thanks again for responding. I have edited the question and added code snippet 3. You mentioned that @SpringBootTest annotation is used more for integration testing. I believe Snippet 3 demonstrates this. So if integration testing is done like in Snippet 3 then what does Snippet 2 do? Snippet 2 uses the SpringBootTest annotation and a mock environment(Default value of the wenEnvironment attribute). Also,snippet 3 starts the embedded server and makes really HTTP calls whereas snippet 2 does not do this. So considering this, cant snippet 2 be considered a unit test? – Revansha Oct 06 '16 at 08:57
  • 6
    I am not sure we're going to sort this out here. Maybe gitter? The thing that you seem to miss constantly is that the application context that `SpringBootTest` and `WebMvcTest` create are vastly different. The former loads your WHOLE app and enables ALL auto-configurations while the latter only enables Spring Mvc and doesn't scan anything but `HelloController`. It all depends what you mean by a unit test after all. But that's the difference. – Stephane Nicoll Oct 06 '16 at 11:02
  • Thanks for your response. That's very helpful for me. Now I understand why my test can run with SpringBootTest but exception when WebMvcTest. Thanks a lot again. – Alps1992 Jan 15 '20 at 14:42
99

@SpringBootTest annotation tells Spring Boot to go and look for a main configuration class (one with @SpringBootApplication for instance), and use that to start a Spring application context. SpringBootTest loads complete application and injects all the beans which can be slow.

@WebMvcTest - for testing the controller layer and you need to provide remaining dependencies required using Mock Objects.

Few more annotations below for your reference.

Testing slices of the application Sometimes you would like to test a simple “slice” of the application instead of auto-configuring the whole application. Spring Boot 1.4 introduces 4 new test annotations:

@WebMvcTest - for testing the controller layer
@JsonTest - for testing the JSON marshalling and unmarshalling
@DataJpaTest - for testing the repository layer
@RestClientTests - for testing REST clients

Refer for more information : https://spring.io/guides/gs/testing-web/

App Work
  • 21,899
  • 5
  • 25
  • 38
RoshanKumar Mutha
  • 2,235
  • 1
  • 12
  • 13
  • 3
    Here is a link to [Sping Boot Reference - Test Auto-configuration Annotations](https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-test-auto-configuration.html#test-auto-configuration). There are more than just the four @roshankumar-mutha has listed here. The link to the getting started guide does not cover these slices in-depth. – George Pantazes Jun 19 '20 at 21:48