Revansha
Revansha

Reputation: 2033

Difference between using MockMvc with SpringBootTest and Using WebMvcTest

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!"));
    }
}

Upvotes: 150

Views: 87127

Answers (3)

work-in-progress
work-in-progress

Reputation: 163

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

Upvotes: 6

RoshanKumar Mutha
RoshanKumar Mutha

Reputation: 2445

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

Upvotes: 105

Stephane Nicoll
Stephane Nicoll

Reputation: 33091

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

Upvotes: 140

Related Questions