写点什么

Spock 单元测试框架实战指南五 - void 方法测试

用户头像
Java老k
关注
发布于: 2020 年 12 月 09 日
Spock单元测试框架实战指南五 - void方法测试

本篇讲解如何针对void方法,即无返回结果的方法测试



void方法



void方法的测试不能像前面几篇介绍的那样在then标签里验证返回结果,因为void方法没有返回值



一般来说无返回值的方法,内部逻辑会修改入参的属性值,比如参数是个对象,那代码里可能会修改它的属性值,虽然没有返回,但还是可以通过校验入参的属性来测试void方法



还有一种更有效的测试方式,就是验证方法内部逻辑和流程是否符合预期,比如:



  • 应该走到哪个分支逻辑?

  • 是否执行了这一行代码?

  • for循环中的代码执行了几次?

  • 变量在方法内部的变化情况?



先看一个void方法的业务代码示例:



/**
* 根据汇率计算金额
* @param userVO
*/
public void setOrderAmountByExchange(UserVO userVO){
if(null == userVO.getUserOrders() || userVO.getUserOrders().size() <= 0){
return ;
}
for(OrderVO orderVO : userVO.getUserOrders()){
BigDecimal amount = orderVO.getAmount();
// 获取汇率(调用汇率接口)
BigDecimal exchange = moneyDAO.getExchangeByCountry(userVO.getCountry());
amount = amount.multiply(exchange); // 根据汇率计算金额
orderVO.setAmount(amount);
}
}



这个void方法主要是遍历userVO下面的订单,通过调用汇率接口计算订单的外币金额,然后再赋值给userVO.orderVO.amount,所以他的核心逻辑在for循环里,那么我们的测试重点就是验证for循环里面的逻辑是否符合预期,金额计算是否正确



代码实现



直接看Spock的测试代码如何写:



/**
* 用户服务测试类
* @author 公众号:Java老K
* 个人博客:www.javakk.com
*/
class UserServiceTest extends Specification {
def userService = new UserService()
def moneyDAO = Mock(MoneyDAO)
void setup() {
userService.userDao = userDao
userService.moneyDAO = moneyDAO
}
def "测试void方法"() {
given: "设置请求参数"
def userVO = new UserVO(name:"James", country: "美国")
userVO.userOrders = [new OrderVO(orderNum: "1", amount: 10000), new OrderVO(orderNum: "2", amount: 1000)]
when: "调用设置订单金额的方法"
userService.setOrderAmountByExchange(userVO)
then: "验证调用获取最新汇率接口的行为是否符合预期: 一共调用2次, 第一次输出的汇率是0.1413, 第二次是0.1421"
2 * moneyDAO.getExchangeByCountry(_) >> 0.1413 >> 0.1421
and: "验证根据汇率计算后的金额结果是否正确"
with(userVO){
userOrders[0].amount == 1413
userOrders[1].amount == 142.1
}
}
}



主要是then标签里的语法: 2 * moneyDAO.getExchangeByCountry(_) >> 0.1413 >> 0.1421,这行代码表示moneyDAO的getExchangeByCountry()方法会被执行2次,第一次输出的结果是0.1413,第二次输出的接口是0.1421



2 * moneyDAO.getExchangeByCountry(_) >> 0.1413 >> 0.1421这行代码也可以分开写,比如只写前面的2 * moneyDAO.getExchangeByCountry(_)



"2 * " 表示方法实际执行的次数, 如果不是2次则不符合预期,单元测试会失败,看你具体的传参,比如在given标签里我们构造的user下面有2个order,订单号分别是1,2,金额分别是1w,1k



那么在调用void方法时,for循环就会循环2次,所以可以通过这样的写法验证我们调用汇率接口的方法是否执行了,以及执行次数



最后在with()方法里会对入参userVO里的订单金额amount进行校验,因为我们设置的两单订单金额分别是1w和1k,then标签已经对汇率接口的返回结果mock了2个不同的汇率值:0.1413、0.1421,那么转换后的外币金额就是1413和142.1元



你也可以将代码改成1 * moneyDAO.getExchangeByCountry(_),然后运行单测,会提示相应的错误信息:



image



报错信息说明实际执行(invoke)了2次



执行几次就写几次,没有执行过就是"0 * ",这正是BDD行为驱动开发思想的体现



(power mock的thenVerify()也可以实现这样的功能,只不过Spock语法更简洁一些)



void + where



如果要结合where测试多分支的void方法时,需要注意一点,因为Spock要求where标签里的表格至少含有两列,如果你的where只是验证入参,也就是只有一列需要验证,那么可以用"_" 表示另外一列值,代码类似下面这样的写法:



where:
requsetParam | _
userVO1 | _
userVO2 | _
userVO3 | _



使用“_”表示任意输入或输出



文章来源:http://javakk.com/297.html



用户头像

Java老k

关注

以梦为码,不负韶华 2018.08.28 加入

十年java老兵,现就职上海某一线互联网大厂,专注java技术,擅长性能调优、JVM诊断、多线程编程,不定期分享面试题和业界最新动态以及人生感悟。

评论

发布
用户头像
该评论已删除
2020 年 12 月 11 日 14:08
回复
2020 年 12 月 14 日 23:41
回复
没有更多了
Spock单元测试框架实战指南五 - void方法测试