Java单元测试Mockito报错:Strict stubbing参数不匹配求助
解决Mockito Strict Stubbing Argument Mismatch(针对JPARepository save/saveAndFlush)
常见触发原因
- Mock存根时指定的参数,和实际调用
save/saveAndFlush传入的对象不相等(比如实体属性差异、未正确重写equals/hashCode) - 用了精确实例匹配,但业务方法内部会创建新对象或修改传入对象的属性,导致存根匹配失败
- Mockito默认严格模式对参数匹配的校验逻辑更严格
具体解决方案
1. 改用参数匹配器替代精确实例匹配
如果无法保证调用时的对象和存根对象完全一致,用any()或指定类型的匹配器:
// 错误写法:精确匹配某个实例,但实际调用时是新对象 when(roleRepository.save(roleStub)).thenReturn(roleStub); // 正确写法:匹配任意Role类型对象 when(roleRepository.save(any(Role.class))).thenReturn(roleStub);
2. 给实体类重写equals和hashCode
如果需要基于属性匹配,确保实体类(比如Role)正确实现这两个方法,让Mockito能判断属性相同的对象为相等:
public class Role { private Long id; private String name; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Role role = (Role) o; return Objects.equals(id, role.id) && Objects.equals(name, role.name); } @Override public int hashCode() { return Objects.hash(id, name); } }
3. 用ArgumentCaptor捕获实际参数排查差异
不确定实际传入的对象是什么时,用捕获器拿到参数后对比属性:
ArgumentCaptor<Role> roleCaptor = ArgumentCaptor.forClass(Role.class); verify(roleRepository).save(roleCaptor.capture()); Role capturedRole = roleCaptor.getValue(); // 打印或断言属性,排查和预期的差异 System.out.println("实际传入的角色名称:" + capturedRole.getName());
4. 临时关闭严格模式(仅调试用)
在测试类上加注解关闭严格模式,快速验证是否为参数匹配问题:
@MockitoSettings(strictness = Strictness.LENIENT) public class RoleServiceTest { // 测试代码 }
测试代码修正示例
原错误测试代码:
@Mock private RoleRepository roleRepository; @InjectMocks private RoleService roleService; @Test void testCreateRole() { Role inputRole = new Role(null, "ADMIN"); Role savedRole = new Role(1L, "ADMIN"); // 错误:用inputRole匹配,但service内部可能修改对象或创建新实例 when(roleRepository.save(inputRole)).thenReturn(savedRole); Role result = roleService.createRole(inputRole); assertEquals(savedRole.getId(), result.getId()); }
修正后代码:
@Test void testCreateRole() { Role inputRole = new Role(null, "ADMIN"); Role savedRole = new Role(1L, "ADMIN"); // 使用参数匹配器兼容任意Role实例 when(roleRepository.save(any(Role.class))).thenReturn(savedRole); Role result = roleService.createRole(inputRole); assertEquals(savedRole.getId(), result.getId()); }
内容的提问来源于stack exchange,提问作者Eduardo Lopes
相关产品推荐
相关产品推荐

