目录

mock 框架验证 API

验证 API 是 mock 框架的一部分,其功能如下:

验证通过检查在执行测试期间构建的调用日志来运行断言。调用日志涵盖让 mock 和 spy 对象在测试中可访问的所有调用。只能验证在 mock/spy 对象上进行的调用。

Verify 类是验证 API 的入口。

@Called 宏用于构建关于代码的断言。

@Called 宏调用构造了一个 验证语句 ,即根据调用日志检查代码的单个断言。

Verify 类本身是静态方法的集合。诸如 that 、 ordered 、 unordered 等方法可构造验证块。

示例

let foo = mock<Foo>()
//配置foo
@On(foo.bar()).returns()
foo.bar()
Verify.that(@Called(foo.bar())) //验证bar至少被调用一次

验证语句和 @Called 宏

验证语句由 VerifyStatement 类表示。 VerifyStatement 实例由 @Called 宏创建。

@Called 宏调用接受桩签名,类似于 @On 宏,并且适用参数匹配器的规则。

示例:

@Called(foo.bar(1, _)) //匹配bar方法调用的验证语句,其中第一个参数为'1'
@Called(foo.baz)       //匹配baz属性getter调用的验证语句

VerifyStatement 类提供的 API 类似于桩配置时可用的基数说明符。

基数函数为:

调用这些函数会返回相同的 VerifyStatement 实例。同一语句不能重置基数,且必须在语句传递到验证块生成器函数之前设置基数。如果没有显式设置基数,则使用默认基数。

Verify.that(@Called(foo.bar()).atLeastOnce())
Verify.that(@Called(foo.bar()).once())

验证块

验证块通常包含一个或多个验证语句,且检查块中的语句会构成更复杂的断言。

在调用验证块时会立即验证,不验证之后发生的任何调用。

验证块不会改变调用日志的状态:日志中的每个调用都可以被任意数量的块检查。独立检查各个块,前后块之间没有依赖关系。除非在块之间发生了一些调用,或者手动清除了调用日志,否则调用验证块的顺序并不重要。

验证语句本身不执行任何类型的验证,必须传递到验证块中进行验证。

单个验证块仅检查在块内验证语句中提到的 mock/spy 对象上的调用,忽略对其他对象的调用。

Verify 类包含几个构建验证块的静态方法。有序验证块用于检查调用的确切顺序。无序验证块只验证调用的次数。

[h2]有序

如需检查一个或多个对象的调用顺序,使用 ordered 验证块生成器。

ordered 静态函数接收一个验证语句数组。

for (i in 0..4) {
    foo.bar(i % 2)
}

Verify.ordered(
    @Called(foo.bar(0)),
    @Called(foo.bar(1)),
    @Called(foo.bar(0)),
    @Called(foo.bar(1))
)

允许检查多个对象的调用顺序。

for (i in 0..4) {
    if (i % 2 == 0) {
        fooEven.bar(i)
    }
    else {
        forOdd.bar(i)
    }
}

Verify.ordered(
    @Called(fooEven.bar(0)),
    @Called(fooOdd.bar(1)),
    @Called(fooEven.bar(2)),
    @Called(fooOdd.bar(3)),
)

有序验证的默认基数说明符是 once() 。如有需要,可使用其他基数说明符。

for (i in 0..4) {
    foo1.bar(i)
}

for (i in 0..4) {
    foo2.bar(i)
}

Verify.ordered(
    @Called(foo1.bar(_).times(4)),
    @Called(foo2.bar(_).times(4))
)

对于有序验证,须列出对(块中提到的) mock/spy 对象的所有调用。任何未列出的调用都会导致验证失败。

foo.bar(0)
foo.bar(10)
foo.bar(1000)

Verify.ordered(
    @Called(foo.bar(0)),
    @Called(foo.bar(10))
)

输出:

验证失败
    以下调用未匹配到任何语句:
        foo.bar(...) at example_test.cj:6

[h2]无序

无序验证只检查其验证语句的调用次数。

对于无序验证,除非显式指定,否则使用 atLeastOnce() 基数,即检查至少进行了一次的调用。

for (i in 0..4) {
    foo.bar(i % 2)
}

//验证是否至少调用了一次使用参数0和参数1的bar
Verify.unordered(
    @Called(foo.bar(0)),
    @Called(foo.bar(1))
)

//验证是否调用了两次使用参数0和参数1的bar
Verify.unordered(
    @Called(foo.bar(0)).times(2),
    @Called(foo.bar(1)).times(2)
)

//验证是否总共调用了四次bar
Verify.unordered(
    @Called(foo.bar(_)).times(4)
)

无序验证包括 Partial 和 Exhaustive 。

默认为 Exhaustive ,需要列出验证语句所提到的 mock/spy 对象的所有调用。

Partial 只列出部分调用。

for (i in 0..4) {
    foo.bar(i)
}

//失败,foo.bar()的两次调用未在块中列出
Verify.unordered(
    @Called(foo.bar(0)).once(),
    @Called(foo.bar(1)).once()
)

//忽略无关调用
Verify.unordered(Partial,
    @Called(foo.bar(0)).once(),
    @Called(foo.bar(1)).once()
)

[h2]动态构建验证块

ordered 和 unordered 函数为接受 lambda 的重载函数。可使用 checkThat(statement: VerifyStatement) 函数动态添加语句。

示例:

let totalTimes = 40
for (i in 0..totalTimes) {
    foo.bar(i % 2)
}

Verify.ordered { v =>
    for (j in 0..totalTimes) {
        v.checkThat(@Called(foo.bar(eq(j % 2))))
    }
}

其他 API

另外,Verify 类还提供了以下工具。