Monday, August 21, 2023

Difference between @SpringBootTest vs @WebMVCTest in Spring Boot

Hello and welcome to yet another blog post. In this article, we are going to take a look at the difference between the two annotations i.e. @SpringBootTest and @WebMVCTest. When developing a Spring Boot application, you may have come across two annotations that are commonly used for testing - @SpringBootTest and @WebMvcTest. Both of these annotations provide ways to test your application, but they differ in their scope and purpose. In the past, I have shared difference between @WebMVCTest and @DataJpaTest and in this article, I Am going to explain the difference between @SpringBootTest and @WebMvcTest in Spring Boot. It's also one of the common Spring Boot testing question and I have also included in my list of popular Spring Boot Testing Questions Earlier, Anyway, before seeing the difference between these two, Let's first look at a quick overview of the @SpringBootTest and @WebMvcTest annotations before figuring out how they differ from one another. 



What is @SpringBootTest Annotation? What does it do?

@SpringBootTest annotation will make Spring Framework scan your application's all three layers such as the Web layer, Service layer, and Data layer. The root package is where Spring Framework will automatically begin examining your application classes. Beans will be created from classes with annotations like @Component, @Repository, @Service, and @Controller, and added to the application context.

The whole application environment will be bootstrapped by @SpringBootTest, allowing us to @Autowire every bean that is discovered during component scanning into our test.

It then enables @Test methods to conduct integration testing after starting the embedded server and creating a web environment.

@SpringBootTest is a more general annotation that loads the entire application context and provides a way to test the application as a whole. It can be used to test the behavior of the application from the top-level perspective, including all the beans, configuration, and auto-configuration that the application has loaded.




What is @WebMVCTest Annotation? What does it do?

@WebMvcTest is a more specific annotation that loads only the web layer of the application. It is primarily used for testing the controller layer of your application, including the request mappings, JSON serialization and deserialization, and other web-related components.

The @WebMvcTest annotation will cause Spring Framework to only scan the @Controller, @ControllerAdvice, @JsonComponent, WebMvcConfigurer, and HandlerMethodArgumentResolver classes, which are linked to MVC infrastructure. Classes containing the @Component, @Service, or @Repository annotation will get skipped.

As mentioned earlier, annotation @WebMvcTest is used to test only the Web Layer of your application.

Additionally, you can select which Controllers to scan using the @WebMvcTest annotation. Spring Framework will only scan the designated Controllers in this scenario.
@WebMvcTest(controllers = YourController.class) 

class YourControllerTest { 

  // Class code goes here

}




Difference between @SpringBootTest vs @WebMvcTest in Spring Boot?

The degree of integration testing offered by these two annotations is one of their main differences. The complete application context, which includes the database, security, and other infrastructure components, is loaded by @SpringBootTest. Because of this, it is better suited for integration testing, in which you want to check how your application's many levels interact with one another.

However, @WebMvcTest is better suited for unit testing the controller layer because it just loads the web layer and mocks out the other levels. By doing this, you can test the behavior of the controller without having to deal with the intricacy of the other levels.

Another difference between these two annotations is the amount of configuration required. @SpringBootTest requires more configuration because it loads the entire application context. This means you may need to provide additional configuration for testing, such as configuring the database and security components.

On the other hand, @WebMvcTest requires less configuration because it only loads the web layer. This means you don't need to provide additional configuration for other layers of your application, which makes it easier to write and maintain tests.

Difference between @SpringBootTest vs @WebMVCTest


Example Demonstration

Consider an application that has a RESTful API that allows users to perform CRUD operations on a database. Let's say you want to test the behavior of the entire application, including the web layer, service layer, and database layer. In this scenario, you would use @SpringBootTest.

Here's an example:
@RunWith(SpringRunner.class)

@SpringBootTest

public class MyApplicationTests {



    @Autowired

    private MyService myService;



    @Autowired

    private MyRepository myRepository;



    @Autowired

    private WebApplicationContext context;



    private MockMvc mockMvc;



    @Before

    public void setup() {

        mockMvc = MockMvcBuilders

                .webAppContextSetup(context)

                .build();

    }



    @Test

    public void testCreateUser() throws Exception {

        MyEntity user = new MyEntity();

        user.setName("John");

        user.setAge(30);



        mockMvc.perform(post("/api/users")

                .contentType(MediaType.APPLICATION_JSON)

                .content(asJsonString(user)))

                .andExpect(status().isOk());



        MyEntity savedUser = myRepository.findById(1L).get();

        assertEquals("John", savedUser.getName());

        assertEquals(30, savedUser.getAge());

    }

}


In this example, we're using @SpringBootTest to load the entire application context and test the behavior of the web layer, service layer, and database layer. We're also using MockMvc to simulate HTTP requests to our RESTful API and test the behavior of the web layer. 

Notice how we're autowiring MyService and MyRepository to test the behavior of the service and database layer, respectively. Now let's consider a scenario where you want to test only the web layer of your application, specifically the controller layer. In this case, you would use @WebMvcTest. Here's an example:


@RunWith(SpringRunner.class)

@WebMvcTest(MyController.class)

public class MyControllerTests {



    @Autowired

    private MockMvc mockMvc;



    @MockBean

    private MyService myService;



    @Test

    public void testGetUser() throws Exception {

        MyEntity user = new MyEntity();

        user.setId(1L);

        user.setName("John");

        user.setAge(30);



        when(myService.getUser(1L)).thenReturn(user);



        mockMvc.perform(get("/api/users/1")

                .contentType(MediaType.APPLICATION_JSON))

                .andExpect(status().isOk())

                .andExpect(jsonPath("$.name", is("John")))

                .andExpect(jsonPath("$.age", is(30)));

    }

}


In this example, we're using @WebMvcTest to test only the web layer of our application, specifically the MyController class. We're also mocking out the service layer using @MockBean so that we can isolate the behavior of the controller layer. 

Notice how we're using MockMvc to simulate HTTP requests and test the behavior of our controller. We're also using the jsonPath method to assert that the response body contains the correct values.

The key difference between these two examples is that the first example uses @SpringBootTest to test the behavior of the entire application, including the service layer and repository layer, while the second example uses @WebMvcTest to test only the behavior of the controller layer, mocking out the service layer. I hope this detailed explanation helps clarify the difference between @SpringBootTest and `@WebMVCTest.



Conclusion 
That's all about the difference between @WebMvcTest and @SpringBootTest annotation in Spring Boot. In conclusion, @SpringBootTest is a more all purpose annotation that loads the context of the entire application and offers a mechanism to test the program as a whole. The more specialized annotation @WebMvcTest, on the other hand, loads only the web layer and is usually used to test the controller layer of your application. Depending on the kind of testing necessary, both annotations are utilized in various contexts and each has its distinct advantages.




No comments:

Post a Comment