如何为从数据库取值的UserServiceImpl的getUserDetails方法编写JUnit测试
UserServiceImpl.getUserDetails 方法JUnit测试实现方案
现有测试存在的问题
- 实例化顺序错误:先调用
userService.getUserDetails()再实例化UserServiceImpl,会直接抛出空指针异常 - 调用方法错误:执行的是未实现的无参
getUserDetails()方法,未覆盖核心的带参业务方法 - 断言无业务意义:仅对比两个固定相同的字符串,未验证任何业务逻辑正确性
推荐实现方案
我们优先采用单元测试+Mock依赖的方案,不需要依赖真实数据库,测试执行速度快、稳定性高;如果需要验证数据库交互逻辑,再选用集成测试方案。
方案1:单元测试(Mockito实现)
前置依赖
确保项目引入JUnit 5 + Mockito测试依赖,Maven配置参考:
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency>
完整测试代码
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.when; import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) public class UserServiceImplTest { // Mock所有外部依赖服务 @Mock private SubsidiaryService subsidiaryService; @Mock private UserGroupService userGroupService; @Mock private ProjectService projectService; // 注入Mock依赖到待测类,如果getUserDetailsById是自身方法请将@InjectMocks改为@Spy @InjectMocks private UserServiceImpl userService; @Test public void testGetUserDetails_WithValidUserId_ReturnCorrectData() { // 1. 构造测试数据 String testUserId = "O635"; // 构造模拟返回的UserDTO UserDTO mockUserDTO = new UserDTO(); mockUserDTO.setUsrCf("O635"); mockUserDTO.setRsqnamCf("test_login"); mockUserDTO.setRsqsecprfCf("ADMIN"); mockUserDTO.setLstupdD(new Date()); mockUserDTO.setRsqpwdCf("test_pwd"); mockUserDTO.setCreusrCf("test_creator"); // 构造模拟返回的用户组列表 UserGroupDTO mockGroupDTO = new UserGroupDTO(); mockGroupDTO.setNameLl("管理员组"); List<UserGroupDTO> mockGroupList = List.of(mockGroupDTO); // 构造模拟返回的项目列表、子公司列表按需补充 List<Project> mockProjectList = new ArrayList<>(); List<ProjDetail> mockProjDetailList = new ArrayList<>(); List<Subsidiary> mockSubsidiaryList = new ArrayList<>(); // 2. 打桩Mock依赖的返回值 when(subsidiaryService.listSubsidariesByUserId(null)).thenReturn(mockSubsidiaryList); when(userService.getUserDetailsById(testUserId)).thenReturn(mockUserDTO); when(userGroupService.listUserGroupByUserId(testUserId)).thenReturn(mockGroupList); when(projectService.listProjectsByUserId(null)).thenReturn(mockProjectList); when(projectService.aggregateProjectDetails(anyList())).thenReturn(mockProjDetailList); // 3. 调用待测方法 AntaresUserDetials result = userService.getUserDetails(testUserId); // 4. 断言返回结果符合预期 assertNotNull(result); assertEquals("O635", result.getId()); assertEquals("sss", result.getFirstName()); assertEquals("sss", result.getLastName()); assertEquals("test_login", result.getLoginId()); assertEquals("ADMIN", result.getUserType()); assertEquals("ADMIN", result.getSecurityProfile().getName()); assertTrue(result.getSecurityProfile().isSelected()); assertEquals(1, result.getUsergroups().size()); assertEquals("管理员组", result.getUsergroups().get(0).getName()); assertTrue(result.getUsergroups().get(0).isSelected()); } }
方案2:集成测试(连接真实测试库)
如果需要验证和数据库的交互逻辑,按以下步骤实现:
- 配置测试环境的数据源,指向专门的测试库,避免影响生产数据
- 测试执行前提前在测试库中插入userId为
O635的用户、用户组、子公司、项目等关联测试数据 - 启动Spring上下文,注入真实的
UserServiceImpl实例 - 调用方法后,断言返回的字段值和数据库中存储的数值完全一致
内容的提问来源于stack exchange,提问作者Ayushi
相关产品推荐
相关产品推荐

