Spring Boot Service层JUnit测试:Dozer对象转换失败求助
问题分析与解决建议
你的问题核心在于Mock了DozerBeanMapper但未正确Stub其map方法,导致Service层调用对象转换时,Mock的Dozer默认返回null,最终生成的EmployeeDTO列表全是null,既无法得到预期的DTO对象,还会导致断言失败(甚至可能触发空指针异常)。另外你的测试断言里写了assertEquals(4, ...),但Mock的Dao只返回了2个Employee,这明显是个笔误,也需要修正。
下面是具体的解决步骤和修改后的代码:
步骤1:准备测试用的EmployeeDTO实例
先创建与Mock返回的Employee对应的DTO对象,用于Stub Doser的转换逻辑。
步骤2:正确Stub Dozer的map方法
使用Mockito的when(...).thenReturn(...),指定当Dozer调用map方法转换某个Employee时,返回对应的EmployeeDTO。如果想通用处理所有Employee的转换,可以用any(Employee.class)来匹配参数。
步骤3:修正断言逻辑
Mock的Dao返回2个Employee,所以Service返回的DTO列表size应该是2,不是4。
修改后的完整测试代码
@SpringBootTest(classes = { EmployeeSearchService.class, EmployeeDao.class }) public class EmployeeSearchServiceTest { @Mock EmployeeDao employeeDao; @InjectMocks private EmployeeSearchService employeeSearchService ; @Mock private DozerBeanMapper dozerBeanMapper; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); } @DisplayName("fetchEmployees with valid data") @Test public void testfetchEmployeesWithValidData() throws IOException { // 1. 准备测试用的Employee和对应的EmployeeDTO Employee emp1 = new Employee(1L, "James", "Java", "Manager", "Google"); Employee emp2 = new Employee(2L, "Richard", "C++", "Manager", "Microsoft"); EmployeeDTO dto1 = new EmployeeDTO(1L, "James", "Java", "Manager", "Google"); EmployeeDTO dto2 = new EmployeeDTO(2L, "Richard", "C++", "Manager", "Microsoft"); // 2. Mock Dao的返回值 when(employeeDao.fetchEmployees()).thenReturn(List.of(emp1, emp2)); // 3. Stub Dozer的map方法:匹配任意Employee,返回对应的DTO;或者精确匹配每个Employee // 方式一:通用匹配(适合批量转换场景) when(dozerBeanMapper.map(Mockito.any(Employee.class), Mockito.eq(EmployeeDTO.class))) .thenAnswer(invocation -> { Employee source = invocation.getArgument(0); // 这里可以手动模拟Dozer的转换逻辑,或者直接返回预定义的DTO if (source.getId().equals(1L)) return dto1; if (source.getId().equals(2L)) return dto2; return null; }); // 方式二:精确匹配每个Employee(更严谨) // when(dozerBeanMapper.map(emp1, EmployeeDTO.class)).thenReturn(dto1); // when(dozerBeanMapper.map(emp2, EmployeeDTO.class)).thenReturn(dto2); // 4. 执行测试并断言 List<EmployeeDTO> result = employeeSearchService.fetchEmployees(); System.out.println(result); assertEquals(2, result.size()); // 修正断言的size值 assertEquals("James", result.get(0).getName()); // 可以添加更细致的断言 } }
额外优化建议
- 如果你不想Mock Dozer,而是想使用真实的Dozer实例来测试转换逻辑,可以去掉
@Mock DozerBeanMapper,改用@Autowired或者手动创建真实实例,这样更贴近实际业务场景(适合需要验证转换规则正确性的测试)。 - 可以改用
@ExtendWith(MockitoExtension.class)替代@SpringBootTest和MockitoAnnotations.initMocks(this),让测试更轻量,不需要加载Spring上下文:@ExtendWith(MockitoExtension.class) public class EmployeeSearchServiceTest { // 其他代码不变 }
内容的提问来源于stack exchange,提问作者Rahiman
相关产品推荐
相关产品推荐

