了解如何在 Exercism 上测试你的 Arturo 练习
Arturo 赛道所有的练习测试都使用 Unitt 3.0.0 单元测试包。
这个包提供了一个测试框架,既支持现代 RSpec 风格的语法,也支持传统的 XUnit 风格语法。
在本地练习文件夹中运行 arturo tester.art 或 exercism test,首次运行时会从互联网安装这个包。
你也可以通过运行 arturo --package install unitt 3.0.0 来安装 Unitt。
只会运行第一个测试,并把结果反馈给你。
这个测试通过后,取消跳过下一个测试,再次运行测试,直到每个测试都通过。
对 RSpec 和 XUnit 两种设置来说,做法都很简单,只要分别从 it.skip 或 test.skip 里去掉 .skip 就行。
所有测试都通过后,就可以提交你的解答,但要注意测试运行器会运行所有测试,包括被跳过的那些。
你下载的练习文件夹里会有一些文件,但下面这三个是必不可少的。
leap/
├── src/leap.art # Your solution file
├── tests/test-leap.art # Test cases for the exercise
└── tester.art # Test runner entry point
运行 arturo tester.art 会先安装好 Unitt,然后运行 tests/test-leap.art 里的测试。
测试会导入包含你解答的 src/leap.art,然后针对具体输入,对你的解答应该返回什么做出一系列断言。
isLeap?: function [year][
panic "please implement the isLeap? function"
]
开始一个练习时,你的解答文件会附带一个模板,其中包含期望的基本结构。
在这个来自 Leap 的例子中,文件里有一个最简版的 isLeap? 函数定义,还有一个会停止测试执行的 panic。
删掉 panic 那一行,然后开始编写 isLeap? 的实现。
import.version:3.0.0 {unitt}!
import {src/leap}!
describe "Leap" [
it "a year not divisible by 4 is a common year" [
expects.be:'false? @[isLeap? 2015]
]
it.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
expects.be:'true? @[isLeap? 1996]
]
]
describe 定义一组验证同一件事的测试用例,可以嵌套。it 和 it.skip 都定义一个测试用例,前者会运行,后者会被跳过。expects 引出测试用例的核心,也就是断言。expects.be 接收一个谓词函数,用来做出断言。在 expects.be:'false? @[isLeap? 2015] 中,测试套件断言函数 isLeap? 对 2015 年应返回 false。
另一种写法是 expects.be:'equal? @[false isLeapYear? 2015],这里我们断言 isLeapYear? 2015 的返回值等于 false。
这种比较两个值的较长写法,是 Arturo 赛道上最常见的断言方式。
在块里,期望值总是排在结果值前面。
suite "Leap" [
test "a year not divisible by 4 is a common year" [
result: isLeap? 2015
assert -> false = result
]
test.skip "a year divisible by 4 and not divisible by 100 is a leap year" [
result: isLeap? 1996
assert -> true = result
]
]
为了向下兼容,Unitt v1 引入的类 XUnit API 仍然受支持,它大体上等同于现代的类 RSpec API,只是断言没那么灵活。
suite 定义一组验证同一件事的测试用例,可以嵌套。test 和 test.skip 都定义一个测试用例,前者会运行,后者会被跳过。assert 引出测试用例的核心,也就是断言。后面 -> 右侧的表达式求值必须为 true。使用 XUnit 测试时,通常会在 assert 行之前创建表示结果的变量,以及可选的期望值。
无论你用的是 RSpec 还是 XUnit API,测试输出都大体相似。
唯一的区别是每个测试名称下面打印的内容。
XUnit 会用求值后的结果来报告断言,所以你会看到 false = false。
而 RSpec 会把它报告成 false? false,因为我们通过 expects 使用了 false? 函数。
从头开始,如果起始文件里的 panic 还没有删掉,Arturo 会报告一个错误,并且不执行任何测试。
Uncaught error in tests/test-leap.art:
#[
output: {
══╡ Program Error ╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ <script> ══
Please implement the isLeap? function
}
code: 1
]
panic 删掉之后,Arturo 会报告测试中每个断言的状态。
现在第一个测试通过了,但第二个测试被跳过。
======== .unitt/tests/test-leap.art ========
Describe: Leap
✅ - assert that a year not divisible by 4 is a common year
✅: false? false
⏩ - assert that a year divisible by 4 and not divisible by 100 is a leap year
skipped!
========== Summary ==========
⏏️ TOTAL: 2 assertions
✅ PASSED: 1 assertion
⏩ SKIPPED: 1 assertion
❌ FAILED: 0 assertion
========== ======= ==========
手动取消跳过第二个测试后,两个测试都会运行。
不过,目前的 isLeap? 代码实现只返回 false,所以第二个测试的断言会失败。
======== .unitt/tests/test-leap.art ========
Describe: Leap
✅ - assert that a year not divisible by 4 is a common year
✅: false? false
❌ - assert that a year divisible by 4 and not divisible by 100 is a leap year
❌: true? false
========== Summary ==========
⏏️ TOTAL: 2 assertions
✅ PASSED: 1 assertion
⏩ SKIPPED: 0 assertion
❌ FAILED: 1 assertion
========== ======= ==========
随着你取消跳过更多测试,这个过程会一直持续。 所有测试通过后,这个练习就完成了,你可以提交解答。 请注意,无论测试是否被跳过,测试运行器在本地都会运行所有测试。