true_H
true_H

Reputation: 85

difference between @SpringBootTest(classes = SomeController.class) and @WebMvcTest(SomeController.class)

I understand that using @SpringbootTest I raise whole spring contex during test, or In my case using @SpringBootTest(classes = SomeController.class) I raise only one bean -> SomeController. If this controller have some dependencies I need to mock them up. Using annotation @WebMvcTest(SoneController.class) I will (based on my knowledge) achieve the same goal.

Question is: Are there any differences between those two annotations used in provided example?

Upvotes: 4

Views: 13426

Answers (3)

Dmitrii B
Dmitrii B

Reputation: 2860

I think for answering your question enough just read the Javadoc for both of these annotations:

1. @WebMvcTest

Annotation that can be used for a Spring MVC test that focuses only on Spring MVC components.

Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. @Controller, @ControllerAdvice, @JsonComponent, Converter/GenericConverter, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not @Component, @Service or @Repository beans).

By default, tests annotated with @WebMvcTest will also auto-configure Spring Security and MockMvc (include support for HtmlUnit WebClient and Selenium WebDriver). For more fine-grained control of MockMVC the @AutoConfigureMockMvc annotation can be used.

@SpringbootTest

Annotation that can be specified on a test class that runs Spring Boot based tests. Provides the following features over and above the regular Spring TestContext Framework:

Uses SpringBootContextLoader as the default ContextLoader when no specific @ContextConfiguration(loader=...) is defined. Automatically searches for a @SpringBootConfiguration when nested @Configuration is not used, and no explicit classes are specified. Allows custom Environment properties to be defined using the properties attribute.

Allows application arguments to be defined using the args attribute. Provides support for different webEnvironment modes, including the ability to start a fully running web server listening on a defined or random port. Registers a TestRestTemplate and/or WebTestClient bean for use in web tests that are using a fully running web server.

Upvotes: 1

Laksitha Ranasingha
Laksitha Ranasingha

Reputation: 4507

There's a clear difference between @SpringBootTest(classes = SomeController.class) and @WebMvcTest(SomeController.class).

  • @SpringBootTest(classes = SomeController.class) - starts a server (i.e like Tomcat) + spring application context with the component SomeController.class. In addition to the controller, you should normally specify the context configuration to successfully start the whole app (For ex: when you don't specify the classes, it falls back to @SpringBootApplication).

  • @WebMvcTest(SomeController.class) - only starts the web layer of the application with SomeController.class.

What's the difference?

@SpringBootTest tests are usually integration tests, you start the full spring-boot application and test against that black box. You can still tweak the application startup by providing configuration, properties, web server type etc in the annotation parameters.

But @WebMvcTest(SomeController.class) is usually a unit test for your controller. These are lightweight and fast. The dependencies like @Service classes are mocked in such tests.

This is a good starting point - https://spring.io/guides/gs/testing-web/

Upvotes: 6

davidxxx
davidxxx

Reputation: 131346

There are several subtle differences between these two ways.
But you will discover a part of them only randomly when you will encounter problems such as bean initialization exception during the spring boot context init or a NullPointerException rising during the test execution.
To make things simpler, focus on intention.
When you write that :

@SpringBootTest(classes = SomeController.class)

you will make Spring to init only the SomeController bean instance.
Is it desirable to test a controller ?
Probably no since you need a way to invoke the controller with a controller approach.
For that a MockMvc instance would help. With WebMvcTest you get that bean additionally loaded in the test context.
So that way is preferable :

@WebMvcTest(SomeController.class)
public class SomeControllerTest{
    
  @Autowired
  private MockMvc mvc;
...
}

Of course you could get a similar behavior with @SpringBootTest and some additional classes but it will be just an overhead : the @WebMvcTest specialized annotation is enough.

At last why make the reading of the test class harder for your follower ?
By weaving a contrived way of using spring boot test annotation, chances are good to come there.

Upvotes: 2

Related Questions