Spring Boot provides a rich set of testing features, consisting of the following two modules:

  • spring-boot-test: Provides core functionality for testing.
  • spring-boot-test-autoconfigure: Provides automatic configuration of tests.

Spring Boot provides a spring-boot-starter-test one-stop starter, as shown in the following dependency configuration.

1
2
3
4
5
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

The Test starter dependency contains not only the two Spring Boot modules above, but also the Spring Test test module, as well as other third-party testing libraries, as shown below.

  • JUnit 5: Java’s most dominant unit testing framework.
  • AssertJ: A fast assertion library.
  • Hamcrest: A unit test matching library.
  • Mockito: a Mock testing framework.
  • JSONassert: a JSON assertion library .
  • JsonPath: A JSON XPath library.

More test-related dependencies can be found in the specific dependency tree, as shown in the following figure.

Dependency trees

These are the common test libraries provided by Spring Boot. If the above test libraries don’t meet your needs, you can add any libraries that are not available above.

Basically, JUnit 5 is used now. if your application is still using JUnit 4 to write unit test cases, you can also use JUnit 5’s Vintage engine to run them, as shown in the dependency configuration below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

The hamcrest-core dependency needs to be excluded because it has changed coordinates and is built into Spring Boot dependency management by default, as shown in the dependency tree above, and the latest Hamcrest coordinates are now org.hamcrest:hamcrest.

Spring Boot provides a @SpringBootTest annotation to be used on unit test classes to enable unit tests that support Spring Boot features, and if you are using JUnit 4, then the @RunWith(SpringRunner.class) annotation is required on the test class. Then just add @Test annotations to the test class methods, each @Test annotated method is a unit test method.

The @SpringBootTest annotation has one of the most important webEnvironment environment parameters and supports the following environment settings:

  • MOCK (default): loads a Web ApplicationContext and provides a Mock Web Environment, but does not start the embedded web server and can be used in combination with the @AutoConfigureMockMvc and @AutoConfigureWebTestClient annotations for Mock testing.
  • RANDOM_PORT: Loads a WebServerApplicationContext, as well as providing a real WebEnvironment and starting the embedded server with a random port.
  • DEFINED_PORT: Same as RANDOM_PORT, the difference is that DEFINED_PORT runs on the port specified by the application, the default port is 8080.
  • NONE: loads an ApplicationContext, but does not provide any Web Environment.

If the @SpringBootTest annotation is used without any parameters, it defaults to the Mock environment.

Real Environment Testing

Specifying a real web environment based on random ports in @SpringBootTest annotation and then injecting TestRestTemplate instances on class member variables or method parameters will complete the real environment testing of Spring MVC interfaces.

The following is a test case for a real environment based on a random port:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MvcTest {
    @Test
    public void getUserTest(@Autowired TestRestTemplate testRestTemplate) {
        Map<String, String> multiValueMap = new HashMap<>();
        multiValueMap.put("username", "Java");
        Result result = testRestTemplate.getForObject("/user/get?username={username}",
        Result.class, multiValueMap);
        assertThat(result.getCode()).isEqualTo(0);
        assertThat(result.getMsg()).isEqualTo("ok");
    }
}

Test the /user/get interface under the current application, pass in the corresponding user name parameter, and finally check if the interface returns the same result as expected, as shown below.

The results of the test.

The unit test passes, and as you can see from the execution log, it starts an embedded Tomcat container to test the real web application environment.

Mock Environment Testing

Mock testing of Spring MVC interfaces can be accomplished by annotating @AutoConfigureMockMvc on classes and then injecting MockMvc instances on class member variables or method parameters.

The following is a test case based on the default Mock environment.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@SpringBootTest
@AutoConfigureMockMvc
class MockMvcTests {
    @Test
    public void getUserTest(@Autowired MockMvc mvc) throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/user/get?username={username}", "test"))
            .andExpect(status().isOk())
            .andExpect(content().string("{\"code\":0,\"msg\":\"ok\",\"
            data\":\"test\"}"));
    }
}

Test the /user/get interface under the current application, pass in the corresponding username parameter, and finally check whether the request status is OK (200) and whether the response is consistent with the expected content.

Results of the test

The unit test passes, and as you can see from the execution log, it does not start a real web environment to test, but uses a Mock environment to test.

Mock Component Testing

There may be times when you need to mock some components, such as some services that can only be invoked after going live and are not available during the development phase, and then you need Mock mock tests that provide various mock components to complete the tests.

Spring Boot provides a @MockBean annotation that defines Mock tests based on Mockito for Bean components in Spring. It can create a new Bean to override an existing Bean in the Spring environment, It can be used on test classes, member variables, or @Configuration configuration classes, member variables, and the mocked bean is automatically reset at the end of each test.

Suppose you now have a remote service userService that cannot be invoked locally, and now you perform a Mock test as shown in the following usage example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@SpringBootTest
class MockBeanTests {
    // @Autowired
    // private UserService userService;
    @MockBean
    private UserService userService;
    @Test
    public void countAllUsers() {
        BDDMockito.given(this.userService.countAllUsers()).willReturn(88);
        assertThat(this.userService.countAllUsers()).isEqualTo(88);
    }
}

The @MockBean annotation here is used on the UserService variable to indicate that this userService instance is covered by Mock in the current test case. If there are multiple beans to be mocked, you can use the @Qualififier annotation to specify them, and then create the mocked return data through the proxy tool class method provided by Mockito. The test will pass when the mocked data matches the expected result.

Here we simulate userService#countAllUsers method by BDDMockito tool class and let it return the total number of users counted (88), and finally check if the return value of the method is as expected.

Results of the test

The unit tests pass, and you can also use the @SpyBean annotation instead of the @MockBean annotation, the difference between the two is:

  • @SpyBean - If no Mockito proxy method is provided, the real bean will be called to get the data.
  • @MockBean - The Mock bean will be called to get the data whether or not a Mockito proxy method is provided.

The @MockBean and @SpyBean annotations can be used in both Mock and real environments. They are only used to simulate and replace the specified bean in the environment, but cannot be used to simulate the behavior of the bean during the application context refresh, because the application context has been refreshed when the test case is executed, so it is impossible to simulate it again. It is recommended to use the @Bean method to create a mock configuration.

Reference: https://blog.csdn.net/weixin_36380516/article/details/130397755