tests/(約 140 檔)· tests/fixtures/ARCHITECTURE.md 講得很清楚:一個模組一個測試檔,全部是純單元測試——不碰網路、不寫 tmp_path 以外的檔案系統。跑法:pytest tests/ -q。
測試量很大(test_extract.py 136KB、test_detect.py 117KB、test_watch.py 135KB、test_languages.py 122KB…),所以這頁是「策略導覽」而不是逐檔翻譯。
fixtures 目錄的心臟是 30+ 個 sample.<ext> 檔案——sample.py、sample.ts、sample.rs、sample.go、sample.java、sample.sql、sample.pas、sample.sv(SystemVerilog)…每種語言一份小樣本。
這讓 test_languages.py 可以用同一套斷言邏輯測所有語言:每個 fixture 都有個別或跨語言的名稱解析測例(test_cross_language_call_resolution、test_csharp_member_calls、test_swift_cross_file_calls、test_java_type_resolution…)。
特殊語料按場景放:cpp_logger/a vs cpp_logger/b(同名檔衝突)、swift_cross_file/(extension)、xaml_viewmodel/(XAML+ViewModels)、pascal_cross_file/、objc_mixed/、crate_a/crate_b(Cargo workspace)。
段落式說明:fixtures 裡有幾個 graphify-out/cache/<sha>.json——預先抽取好的結果。測試直接載入快取,驗證「快取載入 → 建圖」這條路徑,不必每次真的解析。這也測試了快取格式的相容性(改快取格式時這裡會炸)。
這個檔是「測一個純函數模組」的範本,值得整檔讀:
make_graph() 用 build_from_json 從 fixtures 的 extraction.json 建圖——所有測試共用。cluster 回傳 dict、覆蓋所有節點、cohesion_score 的極端值(complete=1.0、單節點=1.0、disconnected=0.0)。test_cluster_does_not_write_to_stdout 用 pytest 的 capsys fixture 驗證 cluster 不會寫 stdout、stderr 不含 ANSI 碼——直接對應 cluster._partition 的「擋 ANSI」行為(issue #19)。remap_communities_to_previous 重用舊 ID、新社群給確定性新 ID。段落式說明:
test_validate.py — 對 validate_extraction 的 schema 測試:缺 nodes/edges key、非 dict、非法 file_type(video 不是允許值)、非法 confidence…test_languages.py(122KB,最大的語言矩陣)— 每個語言的抽取正確性。test_build.py(67KB)— 建圖整合,含 hyperedges、ghost 合併、檔案消歧。test_dedup.py(40KB)— 去重管線逐步測試(對應 dedup 的設計)。test_incremental.py / test_cache.py — 增量與快取(對應 增量設計)。README 的 contributing 章節提醒:測試套件同時有 sample.f90 與 sample.F90(Fortran 兩種大小寫副檔名)。在 macOS 的 HFS+/APFS(大小寫不敏感)上這兩個檔會撞在一起——要同時測兩種 Fortran 變體得在 Linux 或 Docker 跑。
教學價值:一個跨平台專案連「測試檔命名」都要考慮檔案系統大小寫。實務上的 workaround 之一是把區分移到目錄層級。
test_languages.py 測例。前面是「看懂測試策略」;這次是動手補測試:你剛在 extractors 頁加完 Kotlin 支援,現在要用「同一個 fixture 通吃所有語言」的紀律把它測好。
sample.py 的結構——一個 class、幾個函數、跨檔 import、型別註解,讓斷言可以「同構」對應其他語言。kotlin_cross_file/ 目錄(仿 swift_cross_file/),驗證 Phase 2 的類別級 INFERRED 邊。test_kotlin_cross_file_calls。graphify-out/cache/ fixture——測試不必每次真跑 tree-sitter,也順便鎖住快取格式。pytest tests/ -q——確認 140+ 檔沒被新 fixture 弄壞(尤其同名檔衝突、大小寫敏感檔案系統)。tests 頁最容易被跳過的是三個「非典型」測試技巧:
test_cluster_does_not_write_to_stdout 用 pytest 的 capsys 驗證 cluster 不寫 stdout、stderr 不含 ANSI 碼——直接對應 cluster.py 的「擋 graspologic 進度條」行為(issue #19)。測「不該發生的事」和測「該發生的事」一樣重要。remap_communities_to_previous 驗證社群重跑時重用舊 ID、新社群給確定性新 ID——把「重現性」變成可測試的契約,不是口號。graphify-out/cache/<sha>.json 讓測試載入「已知抽取結果」而不是真的解析——快了很多,且順帶鎖住「快取格式的相容性」(改格式這裡會炸)。sample.* fixture 只有一份「樣本」,不代表整個語言。最經典的誤判:新增語言後 pytest tests/ -q 全過,就宣稱「Kotlin 支援完成」——實際上只完成「sample.kt 支援完成」。真實語料的語法變體,要靠「把真實 repo 當 fixture」的 integration 測試才抓得到。| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| 測試在 macOS 上「多出」一堆失敗 | 大小寫不敏感檔案系統讓 sample.f90 / sample.F90 撞檔 | 在 Linux/Docker 跑該測例;或把區分移到目錄層級 |
| 新 fixture 造成別語言測試爆炸 | fixture 檔名撞名(同名 .py/.ts 樣本被誤抓)或 registry 共享狀態 | 檢查 fixture 命名唯一性;跑單一測試檔對比爆炸範圍 |
| 測「快取載入」時測例極慢 | 沒用預算好的 cache fixture,真的在跑 tree-sitter | 把抽取結果預先放進 graphify-out/cache/ fixture |
| 改了 cluster 的 ANSI 處理,測試卻沒抓到 | 沒有 capsys 測例覆蓋「不寫 stdout」契約 | 仿 test_cluster_does_not_write_to_stdout 補測 |
| 某語言「實際 repo」抽錯但測試全綠 | sample fixture 太簡單,沒涵蓋該語言語法變體 | 把真實 repo 縮小成 fixture 加進 tests;補 integration 層測試 |