Spring Boot 进行 MockMvc 单元测试的实例
作者:mmseoamin日期:2024-01-19

在Spring Boot应用程序中,使用MockMvc进行单元测试是一种有效的方式,可以验证控制器的行为和API的正确性。在这篇博客中,我们将介绍如何使用MockMvc对用户控制器(UserController)进行测试,该控制器涉及用户信息的增删改查操作。

UserController测试类

package com.lfsun.mockmvc;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lfsun.mockmvc.entity.User;
import com.lfsun.mockmvc.service.UserService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.Arrays;
import java.util.List;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;
    @Autowired
    private UserService userService;
    @Autowired
    private ObjectMapper objectMapper;
    @Before
    public void setUp() {
        // 在测试前初始化一些数据,或者使用Mockito进行一些mock设置
    }
    @Test
    public void getAllUsersTest() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/user/getAllUsers"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$").isArray())
                .andExpect(jsonPath("$.length()").value(userService.getAllUsers().size()))
                .andDo(print());
    }
    @Test
    public void getUserByIdTest() throws Exception {
        Long userId = 1L;
        mockMvc.perform(MockMvcRequestBuilders.get("/user/getUserById/{userId}", userId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.userId").value(userId))
                .andDo(print());
    }
    @Test
    public void addUserTest() throws Exception {
        User user = new User();
        user.setUsername("testUser");
        user.setEmail("test@lfsun.com");
        mockMvc.perform(MockMvcRequestBuilders.post("/user/addUser")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(user)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.username").value("testUser"))
                .andExpect(jsonPath("$.email").value("test@lfsun.com"))
                .andDo(print());
    }
    @Test
    public void updateUserTest() throws Exception {
        Long userId = 1L;
        User updatedUser = new User();
        updatedUser.setUserId(userId);
        updatedUser.setUsername("updatedUser");
        updatedUser.setEmail("updated@lfsun.com");
        mockMvc.perform(MockMvcRequestBuilders.put("/user/updateUser")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(updatedUser)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.userId").value(userId))
                .andExpect(jsonPath("$.username").value("updatedUser"))
                .andExpect(jsonPath("$.email").value("updated@lfsun.com"))
                .andDo(print());
    }
    @Test
    public void deleteUserTest() throws Exception {
        Long userId = 1L;
        mockMvc.perform(MockMvcRequestBuilders.delete("/user/deleteUser/{userId}", userId))
                .andExpect(status().isOk())
                .andDo(print());
    }
}

解释和注意事项

  1. MockMvc的注入: @Autowired 注解用于将MockMvc实例注入测试类中。
  2. 数据初始化: 使用 @Before 注解的 setUp 方法,可以在测试前进行一些数据初始化或使用Mockito进行一些mock设置。
  3. 测试方法: 每个测试方法使用MockMvc执行相应的HTTP请求,并使用断言验证控制器的响应是否符合预期。
  4. 数据序列化: ObjectMapper 负责将对象序列化为JSON,以便在POST和PUT请求中传递。

以下附上完整代码

controller:

package com.lfsun.mockmvc.controller;
import com.lfsun.mockmvc.entity.User;
import com.lfsun.mockmvc.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * 用户 Controller
 *
 * @author CL
 */
@RestController
@RequestMapping(value = "/user")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;
    // 查询所有用户
    @GetMapping("/getAllUsers")
    public List getAllUsers() {
        return userService.getAllUsers();
    }
    // 根据用户ID查询用户
    @GetMapping("/getUserById/{userId}")
    public User getUserById(@PathVariable Long userId) {
        return userService.getUserById(userId);
    }
    // 添加用户
    @PostMapping("/addUser")
    public User addUser(@RequestBody User user) {
        return userService.addUser(user);
    }
    // 更新用户信息
    @PutMapping("/updateUser")
    public User updateUser(@RequestBody User user) {
        return userService.updateUser(user);
    }
    // 根据用户ID删除用户
    @DeleteMapping("/deleteUser/{userId}")
    public void deleteUser(@PathVariable Long userId) {
        userService.deleteUser(userId);
    }
}

service、serviceimpl

package com.lfsun.mockmvc.service;
import com.lfsun.mockmvc.entity.User;
import java.util.List;
/**
 * 用户 Service 接口
 */
public interface UserService {
    // 查询所有用户
    List getAllUsers();
    // 根据用户ID查询用户
    User getUserById(Long userId);
    // 添加用户
    User addUser(User user);
    // 更新用户信息
    User updateUser(User user);
    // 根据用户ID删除用户
    void deleteUser(Long userId);
}
package com.lfsun.mockmvc.service.impl;
import com.lfsun.mockmvc.entity.User;
import com.lfsun.mockmvc.mapper.UserMapper;
import com.lfsun.mockmvc.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * 用户 Service 实现类
 */
@Service
@AllArgsConstructor  // Lombok 自动生成构造函数
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    @Override
    public List getAllUsers() {
        return userMapper.getAllUsers();
    }
    @Override
    public User getUserById(Long userId) {
        return userMapper.getUserById(userId);
    }
    @Override
    public User addUser(User user) {
        userMapper.addUser(user);
        return user;
    }
    @Override
    public User updateUser(User user) {
        userMapper.updateUser(user);
        return user;
    }
    @Override
    public void deleteUser(Long userId) {
        userMapper.deleteUser(userId);
    }
}

mapper

package com.lfsun.mockmvc.mapper;
import com.lfsun.mockmvc.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
 * 用户 Mapper 接口
 */
@Mapper
public interface UserMapper {
    List getAllUsers();
    User getUserById(Long userId);
    void addUser(User user);
    void updateUser(User user);
    void deleteUser(Long userId);
}

实体类:

package com.lfsun.mockmvc.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long userId;
    private String username;
    private String email;
}

xml



    
        
        
        
    
    
    
    
    
    
    
        INSERT INTO user (username, email)
        VALUES (#{username}, #{email});
    
    
    
        UPDATE user
        SET username = #{username},
            email    = #{email}
        WHERE user_id = #{userId};
    
    
    
        DELETE
        FROM user
        WHERE user_id = #{userId};
    

配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mockmvc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
    username: root
    password: 123321
mybatis:
  mapper-locations: classpath:/mapper/*.xml  # 指定 MyBatis mapper 文件的位置
  configuration:
    map-underscore-to-camel-case: true  # 配置驼峰命名规则

maven



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.7.14
         
    
    com.lfsun
    lfsun-study-mockmvc
    0.0.1-SNAPSHOT
    lfsun-study-mockmvc
    lfsun-study-mockmvc
    
        17
    
    
        
            org.springframework.boot
            spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.projectlombok
            lombok
            provided
        
        
            junit
            junit
            test
        
        
            mysql
            mysql-connector-java
            8.0.23
            compile
        
        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            1.3.2
        
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin