关于单元测试的两个问题请教
问题一
业务
下单页查询优惠券
代码
// 下单页查询可用优惠券
public List<Coupon> getAvailableCoupons(String productCategory, int productPrice, String shopId, String userId){
// 查询所有可用优惠券
List<Coupon> couponList = couponMapper.queryCoupons(userId);
// 筛选优惠券
List<Coupon> availableList = new ArrayList<>();
for (Coupon coupon : couponList) {
// 校验类目券 如图书券不能用于购买手机
if(!checkCategory(coupon,productCategory)){ // 类目不匹配
continue;
}
// 校验满减券 如满100减50
if(!checkPrice(coupon,productPrice)){ // 作品金额不足满减金额
continue;
}
// 校验店铺券
if(!checkShopCoupon(coupon,shopId)){ // 排除其他店铺的优惠券
continue;
}
availableList.add(coupon);
}
return availableList;
}
单元测试代码
@Test
public void test_exclude_coupon_which_belong_to_other_shop(){
// 测试排除了其他店铺券
String productCategory = "book";
int productPrice = 200;
String shopId = RandomStringUtils.randomAlphanumeric(10); //作品所属店铺
String userId = RandomStringUtils.randomAlphanumeric(10);
Coupon coupon = new Coupon();
String anotherShopId = RandomStringUtils.randomAlphanumeric(10);
coupon.setShopId(anotherShopId); // 其他店铺的优惠券
coupon.setCategory("book"); // 图书券
coupon.setFullPrice(200); // 满200减50
coupon.setPrice(50);
when(couponMapper.queryCoupons(userId)).thenReturn(newArrayList(coupon));
List<Coupon> availableCoupons = service.getAvailableCoupons(productCategory, productPrice, shopId, userId);
// 验证 是否排除了其他店铺的优惠券
assertEquals(0, availableCoupons.size());
}
虽然单元测试执行通过了 但是仍没有信心 因为不知是否确实调用了checkShopCoupon 还是直接在前面的校验就失败了 如checkCategory永远都返回false 因为(这些校验)是内部私有方法 没办法通过verify来判断是否调用了
另外每种校验也都有好几种情况 如
校验类目
- 如果是通用券 不限类目 如category_all 返回true
- 否则优惠券的类目列表不含作品类目 返回false
校验金额
- 如果是无门槛券 直接返回true
- 如果是满减券 校验作品金额 是否 大于大于等于 满减金额
是不是单独测试这些校验方法就可以了 如果这样的话 需要将这些私有方法变成protected或包私有
问题二
业务
下单页查询可用优惠券
查询所有可用优惠券
筛选
组装返回Vo
对应的方法为
ResultVo getAvailableCouponsWhenOrder(...){
List<Coupon> couponList = queryAll(userId);
List<Coupon> availableList = filterCoupons(couponList,...);
ResultVo result = buildResultVo(availableList,...);
return result;
}
现在单元测试只想测试筛选优惠券 即filterCoupons 但是它是一个私有方法 那么只好把它改成包私有或者protected了
没有信心的一个原因是测试场景覆盖不全,另一个在缺乏策略,在复杂的控制逻辑中如果要测试某个方法被call过,而该方法是私有的,有一个包可以试一下叫powermock,其中mock私有方法可以成功。很强大,不过在某种程度上,使用到powermock说明,我们写的代码可测试性很差,这是一个问题。
问题二
用上一个方法也可以解决。
建议使用TDD,如果资源自由的情况下,帮助更好思考业务,并且让实现的功能代码天生可测试。