spock数据驱动测试

850 阅读2分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

书接上文,spock提出了很多概念去辅助我们快速mock数据,测试结果。如果这是诸如mockito之类的测试工具也能实现的,那下面的特性才是杀手锏——数据驱动测试。名字起的很好,可能还没到类似DDD那种高度,但首先已经被唬住了。

首先来看一个例子:

class MathSpec extends Specification {
  def "maximum of two numbers"() {
    expect:
    // exercise math method for a few different inputs
    Math.max(1, 3) == 3
    Math.max(7, 4) == 7
    Math.max(0, 0) == 0
  }
}

这是上文提到的一个普通的test case,但这并不是spock想要的效果。如果你的方法有10个分支,那就得在这写至少10行方法调用。代码多就是不正义,下面看一下spock是怎么精简的:

class MathSpec extends Specification {
  def "maximum of two numbers"() {
    expect:
    Math.max(a, b) == c

    where:
    a | b || c
    1 | 3 || 3
    7 | 4 || 7
    0 | 0 || 0
  }
}

这里可以写无限多的行,第一行是表头,下面是输入和期望的输出。具体的格式如下:

输入1 | 输入2 || 输出

当然也可以多写几个输入和输出,和第一行的参数值对应上即可。如果你不想用竖线,用分号也是可以的,毕竟敲起来可能稍微方便一些:

 where:
    a ; b ;; c
    1 ; 3 ;; 3
    7 ; 4 ;; 7
    0 ; 0 ;; 0

对于写法上的花样,spock的开发者还提供了管道的写法,每个变量的值都是一个流水线:

where:
a << [1, 7, 0]
b << [3, 4, 0]
c << [3, 7, 0]

如果你依然还嫌麻烦,spock还提供了多变量的数据管道:

@Shared sql = Sql.newInstance("jdbc:h2:mem:", "org.h2.Driver")

def "maximum of two numbers"() {
  expect:
  Math.max(a, b) == c

  where:
  [a, b, c] << sql.rows("select a, b, c from maxdata")
}

直接从数据库读取,然后直接给对应的变量赋值。如果你恰好又不想在sql中列举这么多字段,spock怎么可能不知道代码从业者的需求:

where:
[a, b, _, c] << sql.rows("select * from maxdata")

不想要的字段,在左侧直接用_忽略即可。如果还想玩出花来,spock也提供了多字段的组合:

where:
[a, [b, _, c]] << [
  ['a1', 'a2'].permutations(),
  [
    ['b1', 'd1', 'c1'],
    ['b2', 'd2', 'c2']
  ]
].combinations()

这段组合的效果就是,a字段会变成['a1','a2']这样的List,中间的d会被忽略掉,b和c就分别对应b1,b2和c1,c2。这里还只是静态数据的罗列,变量计算也是可以支持的:

where:
a | b
3 | a + 1
7 | a + 2
0 | a + 3

在这样的框架体系下,能满足你绝大多数的想象力,应对不同的单测场景,单测似乎也不会那么枯燥了。