Skip to Content

测试与断言(Test)

@Test 标注公开无参函数即为测试函数,mush test 逐条运行并给出摘要。断言族在 std::Test 模块里,失败走 fail 流。

一个测试文件

module Tests; import std::Test.*; @Test public func add_works() { AssertEq(2 + 2, 4); } @Test public func strings_repeat() { Test.AssertEq("ab" * 2, "abab"); }
  • @Test 标注公开、无参、模块级的函数(async 在此处也合法)。
  • mush test 文件.ms 逐条运行,输出 PASS / FAIL / SKIP 与摘要行:
PASS testing.ms::add_works (24.1ms, 0 vticks) PASS testing.ms::strings_repeat (1.7ms, 0 vticks) ms-corpus: 2 passed, 0 failed, 0 skipped

输出行逐字段

(24.1ms, 0 vticks):前者是墙钟真实耗时,后者是虚拟泵步进数:测试跑在每步推进一个 tick(≈16666.67µs)的虚拟钟上,同步用例立即完成就是 0 vticks,await 1s 恰好是 60。失败行下挂结构化 fail 载荷与日志尾部(默认 20 行,收 Test.Log 与 Debug.*):

FAIL basic.ms::d_fails (1.8ms, 0 vticks) Test.AssertEqFailed(msg=AssertEq failed, expected=1, actual=2) 日志尾部: before fail

断言族

函数行为
Test.Assert(cond, msg = "")条件为假即失败
Test.AssertEq(expected, actual, msg = "")值不相等即失败,输出两侧
Test.Fail(msg = "")直接失败
Test.Log(msg)测试日志
Test.WaitForTicks(n)虚拟钟推进 n 个 tick(见下文)
Test.BeforeTick(n)等到第 n 个 tick 之前(纯钟宿主同 WaitForTicks)

断言失败不可被捕获:Assert 族没有 fail 契约,try? Assert(...) 会在编译期直接拒绝。断言失败必然 FAIL 该用例,用例内消费自己的错误时(比如 capture 自己声明的 fail 函数)可以照常通过。

生命周期:@Setup 与 @Teardown

每个用例跑在独立世界里:全局按声明重新初始化,用例之间零共享(上个用例改过的全局,下个用例读到的是初值)。跨用例的初始化与清理用 @Setup / @Teardown:

var counter: int = 0; @Setup public func before_each() { counter = 100; } @Teardown public func after_each() { }
  • 可声明多个 @Setup / @Teardown,按声明序逐个执行,每个用例前 / 后各一次。
  • setup 失败:该用例 FAIL 并带 [setup-failed] 注记,用例体与 teardown 都不跑。
  • teardown 无论成败都跑:失败写进日志。PASS 用例带 [teardown-error] 注记但仍算 PASS,FAIL 用例的失败原因不被覆盖。

tick 与时间

tick 是测试的帧刻度:1 tick = 50000/3 µs ≈ 16666.67µs(16666/16667/16667 交替,零漂移)。WaitForTicks(n) 将用例对齐到帧刻度:WaitForTicks(1) 是 1 个 vtick、WaitForTicks(60) 恰好相当于 await 1s。也可以直接这样写:

BeforeTick(n) 在纯钟宿主下与 WaitForTicks 同义。测试的虚拟钟上限默认 36M µs(10 虚拟分钟),await 3600s 会 FAIL 并带 [virtual-timeout] 注记。

运行细节

  • @Skip 跳过用例:@[Skip("not ready")],输出 SKIP ... (not ready)。
  • mush test 文件 --filter two 按显示名(file::test)子串筛选,大小写不敏感,--list 列出全部用例名,--json / --junit 出机器可读报告,--verbose 让 PASS 用例也打日志。
  • 退出码:0 全部通过、1 有失败、2 用法错。
  • 编译失败的语料记一行 FAIL 文件::<compile> (错误),计入摘要的 broken-files,不会静默消失。
  • 每用例默认燃料 5000 万条指令,烧完 FAIL 并带 [fuel-exhausted]。

注意

  • 测试文件也是普通脚本:mush run 它会跑 main(没有 main 就当库文件编译)。
  • 摘要行 ms-corpus 汇总全部语料:passed / failed / skipped,有坏文件时追加 broken-files。
  • 测试的确定性时序见虚拟时钟。
最后更新于 2026年10月10日