在凹语言中,以 test_xxx.wa
或 xxx_test.wa
形式命名的文件对应测试代码,测试代码可以单文件执行也可以放在工程文件中执行。
1. 斐波那契数列
斐波那契数数列对应一个兔子繁殖的题目,对应的数学定义为:F(0)=1, F(1)=1, F(n)=F(n-1)+F(n-2)
。对应的数列为:1、1、2、3、5、8、13、21、34......。我们现在以凹语言构造这个程序。
创建 fib.wa
文件(不是测试文件),构造一个凹语言斐波那契数列的例子:
wa
func main {
for i := range 10 {
println(Fibonacci(i))
}
}
// 1, 1, 2, 3, 5, ...
func Fibonacci(i: int) => int {
if i >= 2 {
return Fibonacci(i-1) + Fibonacci(i-2)
}
return 1
}
执行结果如下:
arduino
$ wa run fib.wa
1
1
2
3
5
8
13
21
34
55
2. 测试斐波那契数列
为了方便演示,我们可以构造等价的 test_fib.wa
测试文件:
wa
func Example {
for i := range 10 {
println(Fibonacci(i))
}
// Output:
// 1
// 1
// 2
// 3
// 5
// 8
// 13
// 21
// 34
// 55
}
// 1, 1, 2, 3, 5, ...
func Fibonacci(i: int) => int {
if i >= 2 {
return Fibonacci(i-1) + Fibonacci(i-2)
}
return 1
}
其中Example
对应main
函数,其中// Output:
标注的是期望的结果。然后通过wa test
命令以测试的方式运行:
shell
$ wa test test_fib.wa
ok __main__ 97ms
表明测试通过。
3. 构造一个失败的测试
斐波那契数列的输入参数默认都是非负整数,因此如果出现输入负数等无效输入我们希望返回0。构造测试例子:
wa
func ExampleFibonacci_invalid {
println(Fibonacci(-1))
// Output:
// 0
}
重新执行测试:
ini
$ wa test test_fib.wa
---- __main__.ExampleFibonacci_invalid
expect = "0", got = "1"
FAIL __main__ 90ms
测试失败。这时候如果通过-run=Example
参数只运行Example
函数依然是成功的:
ini
$ wa test -run=Example test_fib.wa
ok __main__ 107ms
4. 修复失败的测试
改进函数对负数的输出检查:
wa
func Fibonacci(i: int) => int {
if i < 0 {
return 0
}
if i >= 2 {
return Fibonacci(i-1) + Fibonacci(i-2)
}
return 1
}
重新运行测试:
shell
$ wa test test_fib.wa
ok __main__ 125ms
现在成功了。
5. TestXXX
测试函数
之前都是通过Example
开头的示例测试,通过验证输出的结果来判断测试代码是否正常。这种ExampleXXX
示例测试很像传统的集成测试,每个测试函数类型独立运行的main
函数,并且两次运行之间没有上下文的干扰。
除了测试打印输出,还可以在TestXXX
测试函数中通过assert
函数进行测试。assert
函数是测试环境的内置函数,函数签名如下:
wa
func assert(ok: bool)
func assert(ok: bool, errMessage: string)
第一个参数是必选的测试条件,如果为false
则测试失败。第二个是可选的测试失败时输出的信息。
先构造一个失败的测试:
wa
func TestFibonacci {
assert(Fibonacci(-1) == 1, "expect 0")
}
运行的结果如下:
lua
$ wa test test_fib.wa
assert failed: expect 0 (test_fib.wa:45:8)
module "unittest://test_fib.wa" closed with exit_code(1)
exit status 1
失败的信息中包含了失败的原因和对应的位置。修正后的测试函数如下:
wa
func TestFibonacci {
// assert(Fibonacci(-1) == 1, "expect 0")
assert(Fibonacci(0) == 1)
assert(Fibonacci(1) == 1)
assert(Fibonacci(2) == 2)
assert(Fibonacci(3) == 3)
assert(Fibonacci(4) == 5)
}
6. 异常的测试
之前我们将负数的输出返回了0,现在我们希望在输入错误是抛出异常,代码如下:
wa
func FibonacciV2(i: int) => int {
if i < 0 {
panic("invalid")
}
return Fibonacci(i)
}
要测试异常,必须通过Example
示例测试:
wa
func ExampleFibonacciV2 {
FibonacciV2(-1)
// Output(panic):
// invalid
}
通过// Output(panic):
表注期望输出的异常输出信息。如果有异常并且匹配输出结果则测试通过。
7. 工程中的测试
对于完整的凹语言工程(含有wa.mod
文件),可以将函数的实现和测试代码分别存放便于管理。
8. 小结
凹语言测试框架麻雀虽小五脏俱全,提供了单元测试、集成测试、异常测试,并且支持执行指定的测试函数。