单元测试最佳实践示例汇总

单元测试最佳实践示例汇总

示例一:变不确定为确定

业务

批量发放优惠券 如1张满100减50优惠券2张满200减100优惠券 先去批量创建优惠券,再批量发放优惠券

for(CouponInfo info : couponInfoList){
        Coupon coupon = new Coupon();
        coupon.setCouponCode(UUIDGenerator.getUUID32()); // 动态随机生成优惠券编码 如84678bfd7c1011e6a22b4437e6d0648e
        // ...
        couponList.add(coupon);
}
couponService.batchAdd(couponList); //批量创建优惠券

// 得到Map<CouponCode, 发放张数>
 
couponService.batchSendCouponsToUser(userId, couponCodeCountMap); //批量发放优惠券给某一用户

问题

想校验优惠券实际发放情况 如满200减100发了两张, 满100减50发放了一张, 但是优惠券编码是随机生成的, 没办法在单元测试中得知券和编码的对应关系。

解决

将生成优惠券编码的信息提取到一个独立的方法中,protected修饰,子类可以覆盖。如下所示

protected String getUUID32(CouponInfo couponInfo) {
    return UUIDGenerator.getUUID32();
}

然后单元测试中创建一个内部类继承欲测试的类并覆盖此方法

private static class MockBuyGiftsActivityService extends BuyGiftsActivityService{   
    @Override
    protected String getUUID32(CouponInfo couponInfo) {
            // couponCode同券满减信息 如100_50
            return format("%d_%d",couponInfo.getReachPrice(),couponInfo.getCouponPrice()); 
        }
    }
}

于是单元测试可以这样测

@InjectMocks
private MockBuyGiftsActivityService service; // 实际测试的是该子类
 
// 验证批量发券
ArgumentCaptor<Map<String,Integer>> couponCodeCountMapCaptor = ArgumentCaptor.forClass(Map.class);
verify(couponService).batchSendCouponsToUser(eq(userId),couponCodeCountMapCaptor.capture());
Map<String, Integer> couponCodeCountMap = couponCodeCountMapCaptor.getValue();
assertEquals(2, couponCodeCountMap.size()); // 验证共发了两种券
assertEquals(1, couponCodeCountMap.get("100_50").intValue()); // 验证满100减50发了1张
assertEquals(2, couponCodeCountMap.get("200_100").intValue()); // 验证满200减100发了2张

示例二--修改Mock方法中的对象参数值

业务

同样的业务 只不过将注入couponCode统一放到couponService中去实现了

// 组装couponList
for(CouponInfo info : couponInfoList){
        Coupon coupon = new Coupon();        
        // ...
        couponList.add(coupon);
}
couponService.batchAdd(couponList); //批量创建优惠券

// 得到Map<CouponCode, 发放张数>
 
couponService.batchSendCouponsToUser(userId, couponCodeCountMap); //批量发放优惠券给某一用户

问题

couponService.batchAdd内注入couponCode值

for(Coupon coupon : couponList){
        coupon.setCouponCode(UUIDGenerator.getUUID32()); // 动态随机生成优惠券编码 如84678bfd7c1011e6a22b4437e6d0648e
}

但单元测试实际不会进入mock方法内部

@Mock
private CouponService  couponService;

导致单元测试中couponCode均为空 没办法进行后续验证 因为所有券的编码均为NULL

解决

可以采用下面的解决方法

doAnswer(new Answer() {
    @Override
    public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
        List<Coupon> couponList = invocationOnMock.getArgumentAt(0, List.class); //得到实际artisanCouponModelList参数
        couponList.get(0).setCouponId("100_50"); // 显式指定满100减50元的编码
        couponList.get(1).setCouponId("200_100"); // 显式指定满200减100的编码
        return null;
    }
}).when(couponService).batchAdd(anyList());

相当于在此修改了mock方法中的对象参数 于是后面验证券的发放情况 就方便了 如下所示

// 验证批量发券
ArgumentCaptor<Map<String,Integer>> couponCodeCountMapCaptor = ArgumentCaptor.forClass(Map.class);
verify(couponService).batchSendCouponsToUser(eq(userId),couponCodeCountMapCaptor.capture());
Map<String, Integer> couponCodeCountMap = couponCodeCountMapCaptor.getValue();
assertEquals(2, couponCodeCountMap.size()); // 验证共发了两种券
assertEquals(1, couponCodeCountMap.get("100_50").intValue()); // 验证满100减50发了1张
assertEquals(2, couponCodeCountMap.get("200_100").intValue()); // 验证满200减100发了2张
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值