在 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 行。 你可以用它來找出不符合預期的測試。