在 D 赛道上测试

了解如何在 Exercism 上测试你的 D 练习


每个练习都会提供单元测试。 你来提供实现。 每个文件都会生成一个控制台可执行文件,用来运行这些测试。 运行测试可执行文件时,每个失败的测试都会打印一条消息,测试失败时还会报告非零退出状态码。

注意:每次构建项目时,你的代码都会接受测试套件的检验。 如果你的代码没有通过一个或多个测试,但本身是合法的 D 代码,它仍然会被编译。

完成每个练习的过程如下:

  • 用dub test运行测试
    • 如果你选择不安装 DUB,可以改用dmd source/*.d -de -w -main -unittest,然后运行生成的可执行文件。
  • 对每个单元测试:
    • 解决编译错误,让测试先真正地失败。
    • 只写刚好能让测试通过的实现。
    • 重构你的实现,提升可读性、减少重复,等等。
    • 启用下一个测试

注意: D 语言本身就支持单元测试,所以单元测试通常和实现放在同一个文件里。 单元测试在 main 的函数体之前运行,并在最终的可执行文件中通过**-unittest**编译选项启用。

解读单元测试的输出

如果所有测试都通过,测试输出大概是这样:

$ dub test
             Generating test runner configuration 'dnd-character-test-library' for 'library' (library).
    Starting Performing "unittest" build using dmd for x86_64.
    Building dnd-character ~master: building configuration [dnd-character-test-library]
     Linking dnd-character-test-library
     Running dnd-character-test-library
1 modules passed unittests

当有测试失败时,测试输出可能很难看懂。

$ dub test
             Generating test runner configuration 'dnd-character-test-library' for 'library' (library).
    Starting Performing "unittest" build using dmd for x86_64.
    Building dnd-character ~master: building configuration [dnd-character-test-library]
     Linking dnd-character-test-library
     Running dnd-character-test-library
core.exception.AssertError@source/dnd_character.d(102): unittest failure
----------------
??:? _d_unittestp [0x5568ff91bf05]
source/dnd_character.d:102 void dnd_character.__unittest_L30_C1() [0x5568ff911fee]
??:? void dnd_character.__modtest() [0x5568ff913760]
??:? int core.runtime.runModuleUnitTests().__foreachbody6(object.ModuleInfo*) [0x5568ff928f82]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)).__lambda2(immutable(object.ModuleInfo*)) [0x5568ff9148f7]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))).__foreachbody2(ref rt.sections_elf_shared.DSO) [0x5568ff92003f]
??:? int rt.sections_elf_shared.DSO.opApply(scope int delegate(ref rt.sections_elf_shared.DSO)) [0x5568ff9200d1]
??:? int rt.minfo.moduleinfos_apply(scope int delegate(immutable(object.ModuleInfo*))) [0x5568ff91ffcd]
??:? int object.ModuleInfo.opApply(scope int delegate(object.ModuleInfo*)) [0x5568ff9148c9]
??:? runModuleUnitTests [0x5568ff928db7]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll() [0x5568ff91d248]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x5568ff91d1d5]
??:? _d_run_main2 [0x5568ff91d13e]
??:? _d_run_main [0x5568ff91cf27]
/usr/include/dmd/druntime/import/core/internal/entrypoint.d:29 main [0x5568ff90f8f1]
??:? [0x7f473154a249]
??:? __libc_start_main [0x7f473154a304]
??:? _start [0x5568ff90f7e0]
1/1 modules FAILED unittests
Error Program exited with code 1

这里面有大量详细的堆栈跟踪信息,但重要的是----------------上面那一行:

core.exception.AssertError@source/dnd_character.d(102): unittest failure

这一行告诉你,失败的断言位于dnd_character.d文件的第 102 行。 你可以借此定位到那个不符合预期的测试。