跳转至

测试你的 Zig 代码 — std.testing 与覆盖率

这一章回答三个问题:怎么写、放哪、怎么知道写够了。 写:Zig 把测试做进了语言(test 块)和标准库(std.testing), 零依赖、zig test 一条命令跑全部;放:Zig 社区的哲学是测试和代码同居一个文件, 改代码时被迫看见测试;够:Zig 没有内置覆盖率——用 kcov 补, 但要知道覆盖率报告的两个陷阱,否则数字会骗你。

1. 这一章讲什么

链条位置:第 6 章给了你错误处理,代码会「正确地失败」了; 这一章给你证明它正确的工具。它和第 5 章的 assert 是一对: assert 守运行时不变量(发布时零成本),测试守行为(随时可跑)。

2. 顶层全景

  写   test "名字" { try std.testing.expect...; }
       └─ 四个主力断言:expect / expectEqual / expectEqualStrings / expectError
       └─ std.testing.allocator:专抓泄漏的分配器
  放   和代码同文件 → 命名写成行为描述 → 用注释分组 → 测试之间零依赖
  跑   zig test → 失败时给你「复现命令」(--test-filter)
       └─ error.SkipZigTest 可程序化跳过
  量   Zig 无内置覆盖率 → kcov(仅 Linux)→ 两个陷阱:死代码不进报告、
       覆盖 ≠ 验证

  图说:写、放、跑、量,四步闭环。Zig 前三步都有内置答案,第四步要借外力。

主线例子:原书的 reverseString 测试失败现场——从一条 FAIL 到定位, 走查 zig test 的输出格式和它给的复现命令。

3. 核心原理一:测试是语言的一部分

3.1 test 块

  fn square(x: i32) i32 {
      return x * x;
  }

  test "square function should return the square of a number" {
      try std.testing.expect(square(3) == 9);
      try std.testing.expect(square(-4) == 16);
      try std.testing.expect(square(0) == 0);
  }

test 是关键字:后面跟一个可选的描述字符串,块里是任意代码。 测试块的隐式返回类型是 anyerror!void——测试可以返回错误来表示失败1, 这让它和错误处理无缝:测试里可以直接 try 一个会失败的函数,错误自然变成测试失败。

测试点的覆盖哲学(原书):正数、负数、零都测,因为「用户总有办法输入你没考虑的那种」2。 配套告诫:永远通过的测试和巧克力茶壶一样没用——测试应该挑战代码, 专挑边角、非法输入3。

3.2 故意失败的测试:expectError

第 6 章的 safeSquare(溢出返回错误)配一个故意触发溢出的测试:

  test "safeSquare should return an error on overflow" {
      try std.testing.expectError(error.OverFlow, safeSquare(46341));
      // 46341² 超过 i32 最大值
  }

46341 × 46341 = 2147488281,而 i32 最大是 2147483647——差 4634 就爆。 expectError(期望的错误, 调用) 验证「失败按预期发生」4。 原书的态度值得收:看测试失败是一种验证——证明测试真的在工作; 测试的目标不是证明代码对,而是找出它不对的地方5。

判断(我们的,不是书里的): 「故意触发溢出」这个测试是全书教学上的佳例, 因为它示范了测试设计的关键动作:先想「什么输入会让它坏」。 46341 这个数(√2³¹ 的整数部分)是 i32 平方的精确边界——原书没有解释这个数怎么来的, 我们补上:它是让平方恰好溢出 i32 的最小正整数(2147488281 > 2147483647)。 边界值不是随手挑的,是算出来的。 如果错,会错在: 如果你只测「超大数」(比如 10 亿)而不测 46341 附近, 会漏掉「边界附近行为错乱」这类实现 bug——边界值测的是实现的分界,不只是数学的分界。

3.3 TDD 与三个陷阱

原书对测试驱动开发(TDD:先写测试再写实现)的态度很健康: 值得试,但别为教条而做6。避坑三条7:

  1. 别测编译器:语言特性和标准库函数不用你测,测你自己的代码;
  2. 要具体:一个测试只验一个行为,失败时立刻知道是哪条行为坏了;
  3. 保持独立:测试之间不得互相依赖,否则排错变成解连环。

4. 核心原理二:std.testing 的四个主力

断言 干什么 适用
expect(条件) 条件为假则失败,报行号和表达式 通用布尔判断
expectEqual(期望, 实际) 类型安全的相等比较 数字、结构体等大多数类型
expectEqualStrings(期望, 实际) 字符串专用比较,失败时指出差异处 字节切片(也就是 Zig 的「字符串」)
expectError(期望错误, 调用) 验证错误并集里确实是那个错误 测试失败路径

四个都是 try 前缀:它们返回错误,失败即测试失败8。 std.testing 的官方卖点四条(原书列表):简单、和 zig test 无缝集成、 失败时的诊断信息好、内存泄漏检测9。

5. 核心原理三:testing.allocator——测试期 leak 检测

这是本章最「Zig」的机制。第 9 章会讲分配器;这里先用:

  test "memory allocation should not leak" {
      var allocator = std.testing.allocator;

      const buffer = try allocator.alloc(u8, 1024);
      defer allocator.free(buffer);        // 忘了这行,测试结束时会报泄漏

      // 对 buffer 做操作...
  }

std.testing.allocator 是一个记账的分配器:每次 alloc 记一笔,每次 free 销一笔, 测试结束时还有没销的账,就报错并附指向泄漏点的栈追踪10。

把主线例子走完:

  测试运行
    → alloc(u8, 1024)   记账 +1
    → defer free 登记    (测试正常结束时销账)
    → 测试结束,框架对账
        ├─ 账平        → 测试通过
        └─ 有未销的账   → 测试失败,打印分配发生时的栈追踪

  图说:泄漏从「运行几周后内存暴涨」提前到「测试当场报错」。

这是第 1 章「没有 GC、泄漏归你管」的配套答案:语言不管,但工具替你把关。 (注意:只在测试里有这个分配器;生产代码用什么分配器由你选,第 9 章。)

6. 核心原理四:跑测试与失败现场

6.1 zig test 与输出格式

zig test my_tests.zig 一条命令:编译、逐个跑、汇报11。输出长这样:

  1/3 reverseString should correctly reverse a string...FAIL
  2/3 parseInt should return an error for invalid input...OK
  3/3 memory allocation should not leak...OK

  Tests failed. Use the following command to reproduce the failure:
  zig test my_tests.zig --test-filter reverseString

输出三要素:进度(第几个/共几个)、结果(OK/FAIL)、复现命令12。 失败详情还给文件:行号、失败的测试函数、栈追踪13。

6.2 主线例子:从 FAIL 到定位

走查第一个测试失败的全过程:

步 你看到的 你做的
① 1/3 reverseString...FAIL 知道坏的是哪个测试
② Tests failed. Use... --test-filter reverseString 复制这条命令,只重跑坏的
③ /home/user/...:42:5: ... try std.testing.expectEqualStrings(expected, actual); ^ 光标指到断言那一行,期望值和实际值的差异会打在附近
④ 修 reverseString,重跑 --test-filter 绿了再跑全量

--test-filter 关键词 按名字子串过滤,大测试集里迭代单个函数时是救命功能14。 还有程序化跳过:return error.SkipZigTest; 让测试报告为 skipped, 留着 unfinished business 以后处理15。

6.3 军规(原书四条)

描述性的测试名;边开发边写测试(别等代码缠成一团再补); 涉内存的测试用 testing.allocator;断言别省16。

7. 核心原理五:组织——测试和代码同居

7.1 同文件哲学

Zig 的主流做法:测试写在被测代码的同一个文件里17。三个好处:

  1. 即时上下文:读函数时顺手看到它该怎么用(测试就是最好的用法示例);
  2. 维护同步:改代码时测试就在眼前,没法装看不见;
  3. 认知负担低:不用在文件树里跳来跳去。

代价(我们的补充,不在书里):文件会变长;编译测试目标时会把源码和测试一起编。 Zig 社区认为这买卖划算,zig test 的约定也配合它(测试块在非 test 构建里被忽略)。

7.2 命名与分组

命名三规则(原书):描述行为(calculateTax applies correct rate for basic items); 一套模式走到底(validateInput with valid data returns true / ... invalid data returns false);别在名字里塞 test——test 关键字已经说明了18。 文件里测试多了,用注释当分区头: // Tests for the add function 下面挂一组19。

7.3 独立性与 doctests

再强调独立性:不共享状态、不用跨测试存活的全局变量; 测试里申请的资源用 defer/errdefer 释放,测试失败也要放20。

doctest(文档测试):写在文档注释里的 ``zig 代码块,zig test` 会抽出来跑:

  /// Reverses the given string.
  ///
  /// ```zig
  /// const reversed = reverse("Zig");
  /// // reversed == "giZ"
  /// ```
  pub fn reverse(s: []const u8) []u8 { ... }

一份代码两份产出:文档示例 + 测试21。原书的提醒: 「例子必须是正确的——没有什么比坏例子更毁信誉」。

8. 核心原理六:覆盖率——Zig 不给你的,自己量

8.1 现状

原书一句话点破:Zig 没有内置的覆盖率统计(写书时)22。 替代方案是外部工具,Linux 上推荐 kcov——它不插桩,靠调试信息把程序执行映射回源码行, 直接出 HTML 报告23。

8.2 主线例子(下):四步出报告

步 命令 产物
① 装 sudo apt-get install kcov kcov 本体
② 编 zig build-exe main.zig(Debug 模式自带调试信息) 带调试信息的可执行文件
③ 跑 kcov coverage_output ./main Alice 执行轨迹;coverage_output/index.html 即报告
④ 看 浏览器打开 index.html 每行代码执行了几次,着色显示

程序本身照原书:读命令行参数、打印 Hello, Alice!24。 给测试出覆盖率要把 kcov 接进 zig test:

  zig test test.zig --test-cmd kcov --test-cmd coverage_output --test-cmd-bin

三个参数各管一件事:--test-cmd kcov(用 kcov 跑测试)、 --test-cmd coverage_output(把输出目录传给 kcov)、 --test-cmd-bin(把测试二进制路径追加到 kcov 命令尾)25。 想固化进构建,可以在 build.zig 里加个 -Dcoverage 选项, 开了就设 test command 为 kcov26。

注意(我们的):原书这段 build.zig 示例已经过时。 它写的是旧 API (b.addExecutable("myapp", "src/main.zig")、exe.setBuildMode(...)、 exe.setTestCommand(...)),这些在 0.13 之后的 Zig 里已被新 API (b.addExecutable(.{ .name = ..., .root_source_file = ... }))取代。 概念(构建选项 + 测试命令注入)仍然有效,代码别照抄——这也是第 1 章 「未到 1.0」警告的实证。

8.3 覆盖率数字的两个陷阱

用之前必须知道(原书明列)27:

  1. 没用到的代码根本不进报告:Zig 编译器不编译未被引用的函数, 覆盖率的分母比你想象的小——报告可能给你「过分完整」的错觉;
  2. 覆盖只表示「执行过」,不表示「验证过」:一行代码被跑到、但结果没被任何断言检查, 它照样算 covered。高覆盖率 + 弱断言 = 自欺。

用覆盖数据的三条正经姿势:找缺口(哪些代码没人测、是死代码还是边角?)、 优先保关键路径、回头加强测试28。外加两条限制:kcov 主要是 Linux 的工具, Windows/macOS 要另寻方案;过 kcov 跑有开销,只适合测试场景29。

9. 作者的判断与证据

可核的: test 块语法与隐式返回类型1;四个断言的行为8; testing.allocator 的泄漏报告10;zig test 输出格式与复现命令12; --test-filter14;error.SkipZigTest15;kcov 的四步用法2425; 两个覆盖率陷阱27。

立场: 「测试同文件」是社区惯例而非语言强制(第 13 章的真实项目会把部分测试放 tests/ 目录,原书没提这个变体);「覆盖率没有反而可能是祝福——逼你有测试策略」30 是作者对缺功能的善意解读,听听就好,别当真:想要覆盖率的人还是去装 kcov 了。

10. 边界与局限

缺什么 说明
没有讲测试运行器的高级用法 自定义 test runner(0.11 后的官方能力)、--test-no-exec、并发跑测试等,全章未提
没有 mock/桩的讨论 依赖注入在 Zig 里的惯用手法(传函数指针/接口结构体)没讲,只给了「保持独立」一句话
kcov 一段已经部分过时 除 build.zig 旧 API 外,kcov 本身的版本差异、macOS 现状都可能和书里的不同
集成测试、端到端测试缺席 全章只有单元测试;一个真实项目的测试金字塔(单元/集成/端到端)没有出现
覆盖率工具链只有 kcov 一家 实际上还有 llvm-cov / grcov 等路线,原书只字未提
「测试 performance」未提 第 1 章反复讲性能,但怎么给 Zig 写基准测试(benchmark),全书(除第 12 章提一句 std.testing 计时)基本缺席

11. 可带走的

主线例子,一行走完: zig test 跑出 1/3 reverseString...FAIL → 照抄它给的 --test-filter reverseString 只重跑坏的 → 报错指到断言行 → 修 → 重跑全绿; 覆盖率:zig build-exe → kcov coverage_output ./main → zig test --test-cmd kcov --test-cmd 输出目录 --test-cmd-bin。

  1. 测试是语言特性:test "描述" { ... },隐式返回 anyerror!void,可以 try;
  2. 四个断言:expect(布尔)、expectEqual(类型安全相等)、expectEqualStrings(字符串)、 expectError(验证「按预期失败」);
  3. 边界值是算出来的,不是挑出来的(46341 = i32 平方溢出的最小正整数);
  4. std.testing.allocator 在测试结束对账,泄漏当场现形并附栈追踪;
  5. 测试和代码同文件,名字写成行为描述,注释分组,测试间零共享状态;
  6. 失败时 zig test 给你复现命令(--test-filter),迭代只用这一条;
  7. error.SkipZigTest 程序化跳过未完成的测试;
  8. doctest:文档注释里的 ```zig 代码块会被抽出来跑——示例即测试;
  9. Zig 无内置覆盖率:Linux 用 kcov,--test-cmd 三件套接入 zig test; 记住两个陷阱(死代码不进报告、覆盖 ≠ 验证);
  10. 原书的 build.zig 覆盖示例是旧 API,概念有效、代码勿抄——1.0 之前的常态。

12. 原文地图

主题 原书章 原文位置
test 块与隐式返回类型 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:74(搜「introduces a test block」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:81(搜「anyerror!void」)
「巧克力茶壶」告诫 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:85(搜「chocolate」)
safeSquare 与 46341 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:93(搜「@mulWithOverflow」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:100(搜「46341」)
「找它不对的地方」 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:110(搜「to prove that your code works」)
TDD 与三陷阱 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:112(搜「Test-Driven Development」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:123(搜「Don’t test the compiler」)
std.testing 四卖点 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:147(搜「Simplicity」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:153(搜「Memory leak detection」)
reverseString 测试 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:164(搜「reverseString should correctly」)
四个断言 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:178(搜「std.testing.expect(x == y)」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:182(搜「expectEqual compares」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:187(搜「expectEqualStrings」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:191(搜「expectError verifies」)
parseInt + expectError Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:206(搜「parseInt should return an error」)
testing.allocator Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:223(搜「special allocator」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:241(搜「stack trace leading back」)
zig test 输出与复现命令 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:248(搜「1/3 reverseString」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:253(搜「test-filter reverseString」)
过滤与跳过 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:264(搜「--test-filter parseInt」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:272(搜「return error.SkipZigTest」)
军规四条 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:281(搜「Be Descriptive」)
测试同文件哲学 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:307(搜「keep your tests close」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:324(搜「Immediate context」)
命名三规则 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:338(搜「Be Descriptive」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:349(搜「Avoid redundancy」)
注释分组 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:366(搜「section headers」)
测试独立性与 defer Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:377(搜「independent of one another」)
doctests Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:389(搜「Kill two birds」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:403(搜「automatically extract」)
无内置覆盖率 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:474(搜「doesn’t have built-in support」)
kcov 是什么、为什么 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:480(搜「without special compilation flags」)
四步用法 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:495(搜「apt-get install kcov」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:509(搜「kcov coverage_output ./main」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:525(搜「Hello, Alice」)
--test-cmd 三件套 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:537(搜「--test-cmd」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:544(搜「Specifies kcov」)
build.zig 集成(旧 API) Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:562(搜「b.option(bool」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:589(搜「-Dcoverage」)
覆盖率两陷阱 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:593(搜「doesn’t compile functions」)
覆盖数据三用法与限制 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:602(搜「Identify gaps」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:610(搜「works well on Linux」)
章末 20 题 Chapter 7: Testing Your Zig Code text/13-ch07-chapter-7-testing-your-zig-code.txt:637(搜「Test time」) · text/13-ch07-chapter-7-testing-your-zig-code.txt:767(搜「Answers」)

  1. 出处:「Chapter 7: Testing Your Zig Code」第 72–82 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:74,搜「introduces a test block」;text/13-ch07-chapter-7-testing-your-zig-code.txt:81,搜「anyerror!void」)。 ↩↩

  2. 出处:同章第 50–70 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:61,搜「square(-4) == 16」;text/13-ch07-chapter-7-testing-your-zig-code.txt:70,搜「the one case you didn’t consider」)。 ↩

  3. 出处:同章第 83–88 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:85,搜「chocolate」)。 ↩

  4. 出处:同章第 90–105 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:93,搜「@mulWithOverflow」;text/13-ch07-chapter-7-testing-your-zig-code.txt:100,搜「46341」;text/13-ch07-chapter-7-testing-your-zig-code.txt:101,搜「exceeds the maximum value for i32」)。 ↩

  5. 出处:同章第 107–111 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:110,搜「to prove that your code works」)。 ↩

  6. 出处:同章第 112–119 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:115,搜「planning your tests」)。 ↩

  7. 出处:同章第 121–128 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:123,搜「Don’t test the compiler」)。 ↩

  8. 出处:同章第 176–219 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:178,搜「std.testing.expect(x == y)」;text/13-ch07-chapter-7-testing-your-zig-code.txt:191,搜「expectError verifies」)。 ↩↩

  9. 出处:同章第 145–154 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:147,搜「Simplicity」;text/13-ch07-chapter-7-testing-your-zig-code.txt:153,搜「Memory leak detection」)。 ↩

  10. 出处:同章第 221–243 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:223,搜「special allocator」;text/13-ch07-chapter-7-testing-your-zig-code.txt:241,搜「stack trace leading back」)。 ↩↩

  11. 出处:同章第 417–427 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:420,搜「zig test your_code.zig」)。 ↩

  12. 出处:同章第 428–442 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:429,搜「1/3 test.addition」;text/13-ch07-chapter-7-testing-your-zig-code.txt:433,搜「reproduce the failure」)。 ↩↩

  13. 出处:同章第 445–456 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:446,搜「2/3 test.addition handles negative」;text/13-ch07-chapter-7-testing-your-zig-code.txt:454,搜「file and line number」)。 ↩

  14. 出处:同章第 458–464 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:461,搜「--test-filter addition」)。 ↩↩

  15. 出处:同章第 269–276 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:272,搜「return error.SkipZigTest」)。 ↩↩

  16. 出处:同章第 278–288 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:285,搜「Use the Allocator」)。 ↩

  17. 出处:同章第 294–333 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:307,搜「keep your tests close」;text/13-ch07-chapter-7-testing-your-zig-code.txt:324,搜「Immediate context」)。 ↩

  18. 出处:同章第 335–362 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:349,搜「Avoid redundancy」)。 ↩

  19. 出处:同章第 364–376 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:366,搜「section headers」)。 ↩

  20. 出处:同章第 377–387 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:379,搜「released, even if a test fails」)。 ↩

  21. 出处:同章第 389–405 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:403,搜「automatically extract」)。 ↩

  22. 出处:同章第 473–475 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:474,搜「doesn’t have built-in support」)。 ↩

  23. 出处:同章第 477–487 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:480,搜「without special compilation flags」)。kcov 仓库地址(查阅于 2026-10-19):https://github.com/SimonKagstrom/kcov ↩

  24. 出处:同章第 489–530 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:495,搜「apt-get install kcov」;text/13-ch07-chapter-7-testing-your-zig-code.txt:509,搜「kcov coverage_output ./main」;text/13-ch07-chapter-7-testing-your-zig-code.txt:525,搜「Hello, Alice」)。 ↩↩

  25. 出处:同章第 532–546 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:537,搜「--test-cmd」;text/13-ch07-chapter-7-testing-your-zig-code.txt:544,搜「Specifies kcov」)。 ↩↩

  26. 出处:同章第 547–589 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:562,搜「b.option(bool」;text/13-ch07-chapter-7-testing-your-zig-code.txt:589,搜「-Dcoverage」)。 ↩

  27. 出处:同章第 591–598 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:593,搜「doesn’t compile functions」;text/13-ch07-chapter-7-testing-your-zig-code.txt:596,搜「indicate which parts」)。 ↩↩

  28. 出处:同章第 599–607 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:602,搜「Identify gaps」)。 ↩

  29. 出处:同章第 609–613 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:610,搜「works well on Linux」)。 ↩

  30. 出处:同章第 615–616 段(text/13-ch07-chapter-7-testing-your-zig-code.txt:615,搜「blessing in disguise」)。 ↩