一个午觉引发的写案之 Mockito.when返回null,非预期值

0.0 前言

这是一篇本不想理它,却因网友督促而进行大修的文章(就像白夜对战斗后的牛头人阿姆进行大修一样)。
这是一个因午觉和懒引发的事故,不睡午觉就不会懒,不会有这个事故,不会有这篇文章,不会对它进行大修。
所以,多思考,少百度(百度之前先过脑子);能从上一句话,得出这个结论的人应该不是一般人吧(:。

0.1 过程回溯
  • 大概是这样吧, 反正时间太久,忘得差不多了(请让你的眼睛谨慎食用 * _*)。
  1. 午休后写了一个Mockito的单元测试,Mockito.when 给了一个 null 的结果,不是预期值。
  2. 没过脑子(也许短暂的过了脑子)直接百度了“Mockito.when”,百度给推荐一篇“Mockito.when空指针异常”的文章(我竟然食用了,竟然解决了问题,这94这篇文章出现的终极原因)。
  3. 食用百度推荐的文章后,发现文章中的NullPointerException和Mockito没三毛钱关系(可能有一毛钱关系吧),异常出现是null.method(对,就是用null的对象去调用方法)引起的。
  4. 我竟然从这个上面找到了灵感(哈哈哈……从对Mockito用法的检查转到了对参数的检查),仔仔细细检查参数,然而并没有什么卵用,但这并未让我放弃对参数对象的问题怀疑。
  5. 不得不使用出了终极杀器 debug, 最终发现某个参数对象没重写 equals和hashCode 方法, 至此问题原因确定。
  6. 重新实现参数匹配(ArgumentMatcher),至此问题解决(本想重写 equals和hashCode,奈何本宝宝不会)。
  • 注:参数匹配用的是精确匹配(Mockito.eq),Mockito.any 对完成单元测试任务很爽,对测试没啥用。
1. 问题
  • Mockito单元测试时,实际返回值不是预期值。
  • 参数内容相同的情况下,出现如下图的情况,故我怀疑是 ( : 没用对Mockito。在这里插入图片描述
2. 过程

由于是公司代码不方便贴出来,并且业务相对更复杂也不便于理解, 所以下文的代码出自下面的demo。
demoMockito PowerMock 的demo示例

2.1 反手就一个百度

百度给推荐一篇“Mockito.when空指针异常”的文章。食用后,发现NullPointerException是null.method引起的。参考下面代码:

// mock的代码
Mockito.when(userService.testMethod(user)).thenReturn(result);

// 被单元测试的方法
public User testMethod(User user) {
   -----
   this.otherMethod(String userName);
   -----
}

// 被测试方法调用的方法
private String otherMethod(String userName) {
   return userName.toString(); // 异常出在这, userName 的值是 null。
}

  • 虽然文章内容不当,但是本尊获得了灵感,开始排除了mockito使用不当的可能性,转而从参数匹配上找原因。
2.2 换方向检查问题原因
  • 看了文章的后,开始从参数匹配上去检查原因。
  • 检查了参数内容,没啥问题,但是还是精确匹配不上。
  • 看了mock时参数精确匹配是怎么匹配的,发现是equals 不是 ==。
  • 再次检查参数对象,发现有个参数对象没重写 equals和hashCode 方法。
    @Test // 有返回值的方法匹配, 参数的三类匹配情况
    public void test1(){
        Map mockMap = Mockito.mock(Map.class);
        // 1.精确匹配
        Mockito.when(mockMap.get(11)).thenReturn(111); // 基础类型
        Mockito.when(mockMap.get(Lists.newArrayList("袁紫霞"))).thenReturn("白玉京"); // 引用类型
        TestCase.assertEquals(111, mockMap.get(11));
        TestCase.assertEquals("白玉京", mockMap.get(Lists.newArrayList("袁紫霞")));
    }

在这里插入图片描述
参数对象list的引用地址不同,依然返回预期值。所以精确匹配果然不是==,而是用的 equals 。

3. 解决问题的三种方案
  1. 重写equals、hashCode方法;
  2. 模糊匹配;
  3. 自定义匹配;

本想重写equals、hashCode方法,但是重写不了(分页相关类PageParam出自引入的一个jar中: 公司封装的分页组件中的类);
模糊匹配又达不到测试的效果;
所以采用的第三种自定义匹配解决问题。

代码如下:

    @Test // 引用类型参数,未重写equals方法, 解决方法
    public void test14(){
        long pageNo = 1;
        long pageSize = 20;
        String name = "白玉京";
        User user = new User();
        user.setName(name);
        PageParam pageParam = PageParam.create(pageNo, pageSize);
        // 1.重写equals方法: PageParam未重写equals方法,参数匹配通不过;重写后可通过。
        // Mockito.when(jdbcQueryManager.queryForPageList(user, User.class, pageParam))
        // 	.thenReturn(Lists.newArrayList(user));

        // 2.模糊匹配:Mockito.any() 或 Mockito.any(class)
        // Mockito.when(jdbcQueryManager.queryForPageList(Mockito.eq(user), Mockito.eq(User.class), Mockito.any()))
        // 	.thenReturn(Lists.newArrayList(user));

		// 3.自定义匹配
        ArgumentMatcher<PageParam> argPage = (page) -> page.getPageNo() == pageParam.getPageNo() && page.getPageSize() == pageParam.getPageSize();
        Mockito.when(jdbcQueryManager.queryForPageList(Mockito.eq(user), Mockito.eq(User.class), Mockito.argThat(argPage)))
               .thenReturn(Lists.newArrayList(user));
        TestCase.assertEquals(Lists.newArrayList(user), userServiceImpl.findByName(pageNo, pageSize, name));
    }
4. 总结
  • 小心无大错。
  • Mockito参数精确匹配,直接检查对象相等(equals)就OK了。
  • 实践是检验真理的唯一标准。多思考、多动手,能自己想出来、实践出来的,只要耗费的时间不多,就别百度,脑子才是自己的。
5. 结束语
  • 真相也许94谎言,毕竟是一个妈生的,只是不知道他爸是谁。
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值