使用Mockito编写Controller层POST请求JUnit测试用例遇参数不匹配失败
解决Mockito verify时"Argument(s) are different!"的问题
兄弟,我太懂你这个坑了!之前用Mockito测Controller层POST请求时也踩过一模一样的雷——明明感觉参数都对,结果verify就是报错说参数不一样。核心原因其实很简单:
问题根源
Mockito默认是通过对象引用来判断方法调用的参数是否匹配的。你的AccountMaintenanceSave类没有重写equals()和hashCode()方法,所以哪怕测试时构造的对象和实际业务代码里创建的对象属性完全一致,只要是两个不同的实例,Mockito就会认为参数不匹配,直接抛出"Argument(s) are different!"的错误。
三种解决办法
1. 给实体类重写equals()和hashCode()
这是最规范的做法,直接修改AccountMaintenanceSave类,添加equals和hashCode方法(可以用IDE自动生成,比如IntelliJ的Generate选项):
import java.util.Objects; public class AccountMaintenanceSave { // 你的属性和getter/setter @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AccountMaintenanceSave that = (AccountMaintenanceSave) o; return Objects.equals(nAccountId, that.nAccountId) && Objects.equals(sClientAcctId, that.sClientAcctId) && Objects.equals(sAcctDesc, that.sAcctDesc) && Objects.equals(sLocation, that.sLocation) && Objects.equals(nDeptId, that.nDeptId) && Objects.equals(nAccountCPCMappingid, that.nAccountCPCMappingid) && Objects.equals(nInvestigatorId, that.nInvestigatorId); } @Override public int hashCode() { return Objects.hash(nAccountId, sClientAcctId, sAcctDesc, sLocation, nDeptId, nAccountCPCMappingid, nInvestigatorId); } // 你的toString方法 }
如果用Lombok的话更简单,直接给类加@EqualsAndHashCode注解就行,自动帮你生成这两个方法。
2. 用Mockito参数匹配器灵活匹配参数
如果不想修改实体类(比如是第三方依赖的类,或者不能改源码),可以用Mockito的参数匹配器来绕过引用比较:
- 用
refEq()匹配属性相等的对象:// 假设你要验证service的save方法被调用,参数是预期的AccountMaintenanceSave对象 verify(yourAccountServiceMock).save(refEq(yourExpectedAccountSaveObj));refEq()会忽略对象的引用,只比较所有非静态属性是否相等。 - 自定义匹配逻辑(
argThat()):
如果只需要验证部分属性,可以自己写判断逻辑:verify(yourAccountServiceMock).save(argThat(account -> { return Objects.equals(account.getnAccountId(), expectedAccountId) && Objects.equals(account.getsClientAcctId(), expectedClientAcctId); // 这里可以添加任意你需要验证的属性判断 }));
3. 忽略具体参数,只验证方法调用次数
如果你的测试只关心方法是否被调用过,不关心具体参数是什么,可以用any()匹配器:
verify(yourAccountServiceMock).save(any(AccountMaintenanceSave.class));
注意事项
- 使用参数匹配器时,所有参数都必须用匹配器,不能混合具体值和匹配器。比如
verify(mock).method(actualObj, anyString())是非法的,要么全用具体值,要么全用匹配器。 - 重写equals时要遵循Java的equals契约:自反性、对称性、传递性、一致性,还要正确处理null的情况。
内容的提问来源于stack exchange,提问作者SpringUser
相关产品推荐
相关产品推荐

