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 works
Reference the configuration of the Bootstrap class
Because all configurations are loaded through the Bootstrap class. - In SpringBoot, the @SpringBoottest annotation is mainly used to test based on
Automatic configuration
ApplicationContext, which allows us to set up the Servlet environment in the test context. - The webEnvironment in the @SpringBoottest annotation can have four options:
MOCK
Load 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 passes
MOCK
The environment can alleviate the distress caused by such environmental constraints
@runwith annotation with SpringRunner
- The JUnit framework provides for
Set up the test runner
Basic notes. - We can make the test run at @runwith (springrunner.class)
Spring
Test environment. SpringRunner inheritance SpringJUnit4ClassRunner
It 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 testing
Relational database
Test notes for - @ DataJpaTest annotations
Automatic injection
A variety ofThe Repository class
, that is,Persistent bean
And initialize oneIn-memory database
And the data source that accesses the database. - In test scenarios, we can use it in general
H2
As 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
controllers
Parameter set toXxxController.class
Tells Spring Boot to limit the application context created for this test toFor a given
Controller bean andThe bean
Some 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.param
When 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 @ SpringBootTest
combination
Embed 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 @SpringbooTtest
Automatic configuration
MockMvc 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 effect
Without using real
XxxRepository (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 RestTemplate
Quite the same
It’s just that it’s used specifically forThe test environment
In 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_PORT
Specifies theRandom port
Web 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 use
Mock objects replace real dependent objects
And simulate the real scene to carry out the test work - @ SpringBootTest annotation of SpringBootTest WebEnvironment.
MOCK
Option 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
- 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
- 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
- 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
- To test persistent classes, we use @datajPatest + @runwith (springrunner.class) annotations
- @ DataJpaTest annotations
Automatic injection
Various Repository classes and initialize oneIn-memory database
And the data source that accesses the database. - In the test scenario, tests annotated with @DatajPatest use an embedded in-memory database. We can use H2 as an in-memory database
- It is used in conjunction with @runwith (springrunner.class). This annotation disables full auto-configuration and applies only configurations related to JPA tests.
- 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
- The Mock mechanism uses Mock objects to replace real dependent objects and simulate real scenarios for testing.
- @ 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.
- First, we inject userRepository with the @MockBean annotation,
I'm telling the program I'm going to virtualize this class
- 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_PORT
options - SpringBootTest.WebEnvironment.
RANDOM_PORT
: as aRandom port
Start the entire Spring Boot project and extract thereal
Get 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
- @ SpringBootTest annotation by using SpringBootTest. WebEnvironment. RANDOM_PORT specifies the stochastic Web running environment of the port.
- If we want to use @SpringBooTtest in a test environment, we can test the remote access process directly using the TestRestTemplate
- 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
- In a scenario annotated by @Springboottest, if we
You want to use a MockMvc object
So you can introduce the @AutoConfiguRemockMVC annotation. - By combining the @SpringBooTtest annotation with the @AutoConfiguRemockMVC annotation, the @AutoConfiguRemockMVC annotation will pass through the Spring context loaded by @SpringbooTtest
Automatically configure MockMvc
This 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
- @ SpringBootTest annotations
Can't
Use in conjunction with the @webmvctest annotation - @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