Download the source code

Download this chapter source code

Annotations associated

@SpringBootTest

  • The Bootstrap class is the entry point of the SpringBoot application, so SpringBoot provides a @SpringbooTtest annotation to test the Bootstrap class. This annotation also worksReference the configuration of the Bootstrap classBecause all configurations are loaded through the Bootstrap class.
  • In SpringBoot, the @SpringBoottest annotation is mainly used to test based onAutomatic configurationApplicationContext, which allows us to set up the Servlet environment in the test context.
  • The webEnvironment in the @SpringBoottest annotation can have four options:
    • MOCKLoad the WebApplicationContext and provide a Mock Servlet environment without the built-in Servlet container being officially launched.
    • RANDOM_PORT: load EmbeddedWebApplicationContext and provide a real Servlet environment, then use a random port to start the built-in container.
    • DEFINED_PORT: is this configuration by loading EmbeddedWebApplicationContext provide a true Servlet environment, but use the default port, if there is no configuration port is 8080.
    • NONE: loads the ApplicationContext without providing any real Servlet environment.
  • In most cases, a real Servlet environment is too heavy for testing and passesMOCKThe environment can alleviate the distress caused by such environmental constraints

@runwith annotation with SpringRunner

  • The JUnit framework provides forSet up the test runnerBasic notes.
  • We can make the test run at @runwith (springrunner.class)SpringTest environment.
  • SpringRunner inheritance SpringJUnit4ClassRunnerIt runs in a Spring environment and allows JUnit to run in conjunction with Spring TestContext, which provides support for testing spring applications in general.

@Test

Basic test annotations used in JUnit to indicate test cases that need to be executed

@DataJpaTest

  • Designed for testingRelational databaseTest notes for
  • @ DataJpaTest annotationsAutomatic injectionA variety ofThe Repository class, that is,Persistent beanAnd initialize oneIn-memory databaseAnd the data source that accesses the database.
  • In test scenarios, we can use it in generalH2As an in-memory database, and through MySQL to achieve data persistence

@MockBean

  • Test annotations to implement the Mock mechanism
  • Automatically replace beans of the same type in the application context with Mockito emulation.

@WebMvcTest

  • Embed MockMvc annotations in the Web container environment
  • The @Springboottest annotation cannot be used at the same time as the @webMvctest annotation.
  • This annotation initializes the Spring MVC infrastructure necessary to test the Controller
    • controllersParameter set toXxxController.classTells Spring Boot to limit the application context created for this test toFor a givenController bean andThe beanSome framework beans related to some Spring Web MVC requirements.
  • The MockMvc class provides six basic methods
    • Perform: Executes a RequestBuilder request, which automatically executes the SpringMVC process and maps it to the appropriate Controller for processing.
    • get/post/put/delete: Specifies how to send an HTTP request based on the URI template and URI variables. HTTP methods such as GET, POST, PUT, and DELETE are supported.
    • paramWhen sending JSON data, use the @responseBody annotation instead.
    • andExpect: Adds a ResultMatcher verification rule to verify the Controller execution result by judging the returned data.
    • andDo: adds a ResultHandler ResultHandler, such as printing results to the console during debugging.
    • andReturn: Finally returns the corresponding MvcResult, and then performs custom validation or asynchronous processing.

@AutoConfigureMockMvc

  • @ AutoConfigureMockMvc with @ SpringBootTestcombinationEmbed MockMvc annotations. In a scenario where we use @SpringBooTtest annotations, we can introduce @AutoConfiguRemockMVC annotations if we want to use a MockMvc object.
  • By combining the @SpringBooTtest annotation with the @AutoConfiguRemockMVC annotation, the @AutoConfiguRemockMVC annotation will pass through the Spring context loaded by @SpringbooTtestAutomatic configurationMockMvc is a class.
Note the name Notes describe
@SpringBootTest Test annotations specific to Spring Boot applications
@RunWith Basic annotations provided by the JUnit framework for setting up test runners
@Test Basic test annotations used in JUnit to indicate test cases that need to be executed
@DataJpaTest Test annotations designed to test a relational database
@MockBea Test annotations to implement the Mock mechanism
@WebMvcTest Embed MockMvc annotations in the Web container environment
@AutoConfigureMockMvc Annotations embedded in MockMvc combined with @Springboottest

Related instructions

TestEntityManager

  • It has the same effectWithout using realXxxRepository (also known as persistence beans) performs data persistence, providing a mechanism for isolating data from the environment.

TestRestTemplate

  • The TestRestTemplate provided by Spring Boot initiates requests in the same way as the RestTemplateQuite the sameIt’s just that it’s used specifically forThe test environmentIn the.
  • If we want to use @SpringBooTtest in a test environment, we can test the remote access process directly using the TestRestTemplate
  • @ SpringBootTest annotation by using SpringBootTest WebEnvironment.RANDOM_PORTSpecifies theRandom portWeb runtime environment. We then make an HTTP request based on the TestRestTemplate and verify the results.

The Mock mechanism

  • Mock means Mock, and it can be used to isolate systems, components, or classes.
  • In the testing process, we usually focus on the function and behavior of the test object itself, while some dependencies involved in the test object only focus on the interaction between them and the test object (such as whether to call, when to call, call parameters, call times and order, as well as returned results or exceptions). You don’t care about the specifics of how these dependent objects perform the call. Therefore, the Mock mechanism is to useMock objects replace real dependent objectsAnd simulate the real scene to carry out the test work
  • @ SpringBootTest annotation of SpringBootTest WebEnvironment.MOCKOption to load the WebApplicationContext and provide a Mock Servlet environment with a built-in Servlet containerIt didn't actually start.

The test of actual combat

The premise

  1. Initialize data
DELETE FROM user;

INSERT INTO user (id, name, age, email)
VALUES (1.'Jone'.18.'[email protected]'),
       (2.'Jack'.20.'[email protected]'),
       (3.'Tom'.28.'[email protected]'),
       (4.'Sandy'.21.'[email protected]'),
       (5.'Billie'.24.'[email protected]');
Copy the code
  1. Pom depends on
<! -- We need a Web application -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<! - simplify -- -- >
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<! -- SpringBoot test module -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<! -- We want to isolate the database environment and use the in-memory database -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
<! -- We want to develop the environment using mysql database -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<! -- Persistence Framework -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<! -- Junit Test component -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
Copy the code

Note: By placing mysql configuration under SRC /main/resources/ and H2 configuration under SRC /test/resources/, SpringBoot automatically helps us run different configuration files in different environments

  1. Entity class
/ * * *@Description: Entity class * GenerationType: * TABLE: Uses a specific database TABLE to hold the primary key. * SEQUENCE: Generate primary keys based on the SEQUENCE of the underlying database, provided that the database supports sequences. * IDENTITY: the primary key is automatically generated by the database (mainly auto-growing) * AUTO: the primary key is programmatically controlled to select one of the above policies. *@Author: jianweil
 * @date: 2021/11/22 17:29 * /
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
//@Proxy(lazy = false)
public class User {
    @Id
    // The h2GenerationType.AUTO program is configured to help us use generationType. SEQUENCE
    //@GeneratedValue(strategy = GenerationType.AUTO)
    / / the serialization
    //@GeneratedValue(strategy = GenerationType.SEQUENCE)
    // https://www.cnblogs.com/hongchengshise/p/10612301.html
    // Database increment
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @Column
    private Integer age;

    @Column
    private String email;
}
Copy the code

Test the persistence layer – DAO

Methods 1. @ DataJpaTest

  1. To test persistent classes, we use @datajPatest + @runwith (springrunner.class) annotations
  2. @ DataJpaTest annotationsAutomatic injectionVarious Repository classes and initialize oneIn-memory databaseAnd the data source that accesses the database.
  3. In the test scenario, tests annotated with @DatajPatest use an embedded in-memory database. We can use H2 as an in-memory database
  4. It is used in conjunction with @runwith (springrunner.class). This annotation disables full auto-configuration and applies only configurations related to JPA tests.
  5. User1 inserts an ID of 6 because H2 initializes five records to the in-memory database
@RunWith(SpringRunner.class)
@DataJpaTest
public class TestDao {

    /** * The effect is to persist data without using a real UserRepository, providing an isolation mechanism between data and the environment. * /
    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private UserRepository userRepository;

    / * * *@throws Exception
     */
    @Test
    public void testGetById(a) throws Exception {
        String expected = "[email protected]";
        User user1 = new User();
        user1.setName("new6");
        user1.setAge(6);
        user1.setEmail(expected);
        //User user3 = this.userRepository.save(user1);
        //User id increment policy IDENTITY policy: store id=6 in h2 database where the data is initialized
        SEQUENCE policy: use the new empty H2 database to save id=1
        // Same effect as above
        this.entityManager.persist(user1);

        User user2 = new User();
        user2.setName("new7");
        user2.setAge(7);
        user2.setEmail("[email protected]");
        //User user4 = this.userRepository.save(user2);
        this.entityManager.persist(user2);

        User user6 = this.userRepository.getById(6L);
        User user7 = this.userRepository.getById(7L);

        Assert.assertNotNull(user6);
        Assert.assertEquals(expected, user6.getEmail());

        Assert.assertEquals("[email protected]", user7.getEmail()); }}Copy the code

Test the business layer-service

Approach 1. Use a Mock mechanism to simulate data

  1. The Mock mechanism uses Mock objects to replace real dependent objects and simulate real scenarios for testing.
  2. @ SpringBootTest annotation of SpringBootTest. WebEnvironment. MOCK option, this option is used to load WebApplicationContext and provides a MOCK Servlet environment, The built-in Servlet container is not actually started.
  3. First, we inject userRepository with the @MockBean annotation,I'm telling the program I'm going to virtualize this class
  4. We then Mock the getById() method in userRepository based on the when/thenReturn mechanism provided by the third-party Mock framework Mockito.That is to tell the program I dummy this class this method, you don't go to the real database, use my return

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class TestServiceMock {
    / * * *@MockBeanIsolate data */
    @MockBean
    private UserRepository userRepository;

    @Resource
    private UserService userService;

    @Test
    public void testGetById(a) throws Exception {
        Long id = 22L;
        // Mock the userRepository.getById(id) data required by the test method userService.findById(22L).
        Mockito.when(userRepository.getById(id)).thenReturn(new User(22L."MockBean".22."[email protected]"));
        User user = userService.findById(22L);
        Assert.assertNotNull(user);
        Assert.assertEquals("MockBean", user.getName()); }}Copy the code

Method 2. Test the database directly

  • If you wish to test cases into real userRepository directly, then you can use @ SpringBootTest annotation of SpringBootTest. WebEnvironment.RANDOM_PORToptions
  • SpringBootTest.WebEnvironment.RANDOM_PORT: as aRandom portStart the entire Spring Boot project and extract therealGet target data for validation.

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestServiceNoMock {
    /** * inject real database */

    @Resource
    private UserService userService;

    /** * error: no seesion is found. Annotate transactions@Transactional* 2. Entity class add@Proxy(lazy = false) * 3. Add the spring configuration file. The jpa. Properties. Hibernate. Enable_lazy_load_no_trans = true * *@throws Exception
     */
    @Test
    @Transactional
    public void testGetById(a) throws Exception {
        Long id = 1L;
        User user = userService.findById(id);
        Assert.assertNotNull(user);
        Assert.assertEquals("Jone", user.getName()); }}Copy the code

Test control layer -Controller

Methods 1. @ SpringBootTest + TestRestTemplate + @ MockBean

  1. @ SpringBootTest annotation by using SpringBootTest. WebEnvironment. RANDOM_PORT specifies the stochastic Web running environment of the port.
  2. If we want to use @SpringBooTtest in a test environment, we can test the remote access process directly using the TestRestTemplate
  3. The TestRestTemplate provided by Spring Boot is very similar to the RestTemplate, except that it is specifically used in test environments.
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestController {

    @Autowired
    private TestRestTemplate testRestTemplate;

    @MockBean
    private UserService userService;

    @Test
    public void testGetById(a) throws Exception {
        Long userId = 1L;
        given(this.userService.findById(userId))
                .willReturn(new User(1L."MockBean".44."[email protected]"));
        PostForObject is a POST request
        ResponseEntity<User> responseEntity = testRestTemplate.exchange("/user/" + userId, HttpMethod.GET, null, User.class);
        Assert.assertEquals("[email protected]", responseEntity.getBody().getEmail()); }}Copy the code

Methods 2. @ @ AutoConfigureMockMvc SpringBootTest + + @ MockBean

  1. In a scenario annotated by @Springboottest, if weYou want to use a MockMvc objectSo you can introduce the @AutoConfiguRemockMVC annotation.
  2. By combining the @SpringBooTtest annotation with the @AutoConfiguRemockMVC annotation, the @AutoConfiguRemockMVC annotation will pass through the Spring context loaded by @SpringbooTtestAutomatically configure MockMvcThis class.
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TestSpringBootTestController {

    @Autowired
    private MockMvc mvc;

    /** ** simulated */
    @MockBean
    private UserService userService;

    @Test
    public void testGetById(a) throws Exception {
        Long userId = 55L;
        // Simulate the implementation
        given(this.userService.findById(userId))
                .willReturn(new User(55L."MockBean".55."[email protected]"));
        this.mvc.perform(org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get("/user/"+ userId).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); }}Copy the code

Methods 3. @ WebMvcTest + @ MockBean

  1. @ SpringBootTest annotationsCan'tUse in conjunction with the @webmvctest annotation
  2. @webmvctest (userController.class) This annotation initializes the Spring MVC infrastructure necessary to test UserController, i.e. related beans, not all beans are loaded, If not, Spring Boot will include all controllers in the context of the application.
@RunWith(SpringRunner.class)
@WebMvcTest(UserController.class)
public class TestWebMvcTestController {

    @Autowired
    private MockMvc mvc;

    /** ** simulated */
    @MockBean
    private UserService userService;

    @Test
    public void testGetById(a) throws Exception {
        Long userId = 55L;
        // Simulate the implementation
        given(this.userService.findById(userId))
                .willReturn(new User(55L."MockBean".55."[email protected]"));
        this.mvc.perform(get("/user/"+ userId).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); }}Copy the code