测试与断言(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日
