Difference between using MockMvc with SpringBootTest and Using WebMvcTest
Asked Answered
G

3

147

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!"));
    }
}
Gauffer answered 5/10, 2016 at 4:44 Comment(0)
D
136

@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.

Dice answered 5/10, 2016 at 8:36 Comment(6)
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?Gauffer
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).Dice
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?Gauffer
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.Dice
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.Billups
OP was asking about @MockMvc with Spring Boot, What is MockMvc mocking ?, If we were doing Full integration tests and someone wants to test the Controller, do we use the Rest client like it would be when calling third party API's ?Bakker
S
103

@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/

Stereotaxis answered 23/5, 2017 at 6:47 Comment(1)
Here is a link to Sping Boot Reference - Test Auto-configuration Annotations. 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.Tokay
H
3

it is really simple.

When you use this combo

@SpringBootTest
@AutoConfigureMockMvc

spring will create :

  • all Controller layer beans
  • all Service layer beans
  • all Repository beans

When you use this single annotation

@WebMvcTest(HelloController.class)

spring will create :

  • only your HelloController bean
  • no Service layer bean
  • no Repository bean

except if you explicitly declare some beans :

  • by using an inner static class with a @TestConfiguration annotation
  • by using an external @TestConfiguration with an @Import annotation
Hygrograph answered 26/1 at 18:4 Comment(1)
What is @MockMvc then ? It it is an integration test, why is it called that ?Bakker

© 2022 - 2024 — McMap. All rights reserved.