Unit Test
- 小型測試帶來優秀的代碼質量、良好的異常處理、優雅的錯誤報告;大中型測試會帶來整體產品質量和數據驗證。
- 不同類型的項目,對測試的需求不同,總體上有一個經驗法則,即70/20/10原則:70%是小型測試,20%是中型測試,10%是大型測試。
- 如果一個項目是面向用戶的,擁有較高的集成度,或者用戶接口比較複雜,他們就應該有更多的中型和大型測試;如果是基礎平台或者面向數據的項目,例如索引或網絡爬蟲,則最好有大量的小型測試,中型測試和大型測試的數量要求會少很多。

"自動化實現的,用於驗證一個單獨函數或獨立功能模塊的代碼是否按照預期工作,著重於典型功能性問題、數據損壞、錯誤條件和大小差一錯誤(譯註:大小差一(off-by-one)錯誤是一類常見的程序設計錯誤)等方面的驗證" - 《Google軟件測試之道》
- 正確的對容器內服務進行健康檢測,避免unittest 啟動時候資源還未 ready
- 應該交由 app 自己來初始化數據,比如 db 的scheme,初始的 sql 數據等,為了滿足測試的一致性,在每次結束後,都會銷毀容器

- 在單元測試開始前,導入封裝好的 testing 庫,方便啟動和銷毀容器。
- 對於 service 的單元測試,使用 gomock 等庫把 dao mock 掉,所以在設計包的時候,應該面向抽象編程。
- 在本地執行依賴 Docker,在 CI 環境裡執行Unittest,需要考慮在物理機裡的 Docker 網絡,或者在 Docker 裡再次啟動一個 Docker

單元測試的基本要求:
- 快速
- 環境一致
- 任意順序
- 並行 (https://eleni.blog/2019/05/11/parallel-test-execution-in-go/)
基於 docker-compose 實現跨平台跨語言環境的容器依賴管理方案,以解決運行 unittest 場景下的(mysql, redis, mc)容器依賴問題:
- 本地安裝 Docker。
- 無侵入式的環境初始化。
- 快速重置環境。
- 隨時隨地運行(不依賴外部服務)。
- 語義式 API 聲明資源。
- 真實外部依賴,而非 in-process 模擬。
Using Subtests and Sub-benchmarks
func TestFoo(t *testing.T) {
// <setup code>
t.Run("A=1", func(t *testing.T) { ... })
t.Run("A=2", func(t *testing.T) { ... })
t.Run("B=1", func(t *testing.T) {
if !test(foo{B:1}) {
t.Fail()
}
})
// <tear-down code>
}
Run a group of tests in parallel The above semantics allows for running a group of tests in parallel with each other but not with other parallel tests:
func TestGroupedParallel(t *testing.T) {
for _, tc := range testCases {
tc := tc // capture range variable
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()
if got := foo(tc.in); got != tc.out {
t.Errorf("got %v; want %v", got, tc.out)
}
...
})
}
}
Cleaning up after a group of parallel tests In the previous example we used the semantics to wait on a group of parallel tests to complete before commencing other tests. The same technique can be used to clean up after a group of parallel tests that share common resources:
func TestTeardownParallel(t *testing.T) {
// <setup code>
// This Run will not return until its parallel subtests complete.
t.Run("group", func(t *testing.T) {
t.Run("Test1", parallelTest1)
t.Run("Test2", parallelTest2)
t.Run("Test3", parallelTest3)
})
// <tear-down code>
}
利用 go 官方提供的: Subtests + Gomock 完成整個單元測試。
- /api
- 比較適合進行集成測試,直接測試 API,使用 API 測試框架(例如: yapi),維護大量業務測試 case。
- Yapi
- /data
- docker compose 把底層基礎設施真實模擬,因此可以去掉 infra 的抽象層。
- /biz
- 依賴 repo、rpc client,利用 gomock 模擬 interface 的實現,來進行業務單元測試。
- /service
- 依賴 biz 的實現,構建 biz 的實現類傳入,進行單元測試。
基於 git branch 進行 feature 開發,本地進行 unittest,之後提交 gitlab merge request 進行 CI 的單元測試,基於 feature branch 進行構建,完成功能測試,之後合併 master,進行集成測試,上線後進行回歸測試。
Reference
- https://www.ardanlabs.com/blog/2017/02/package-oriented-design.html
- https://www.ardanlabs.com/blog/2017/02/design-philosophy-on-packaging.html
- https://github.com/golang-standards/project-layout
- https://github.com/golang-standards/project-layout/blob/master/README_zh.md
- https://www.cnblogs.com/zxf330301/p/6534643.html
- https://blog.csdn.net/k6T9Q8XKs6iIkZPPIFq/article/details/109192475?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160561008419724839224387%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160561008419724839224387&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v28-6-109192475.first_rank_ecpm_v3_pc_rank_v2&utm_term=阿里技术专家详解DDD系列&spm=1018.2118.3001.4449
- https://blog.csdn.net/chikuai9995/article/details/100723540?biz_id=102&utm_term=阿里技术专家详解DDD系列&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-100723540&spm=1018.2118.3001.4449
- https://blog.csdn.net/Taobaojishu/article/details/101444324?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160561008419724838528569%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160561008419724838528569&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-101444324.first_rank_ecpm_v3_pc_rank_v2&utm_term=阿里技术专家详解DDD系列&spm=1018.2118.3001.4449
- https://blog.csdn.net/taobaojishu/article/details/106152641
- https://cloud.google.com/apis/design/errors
- https://kb.cnblogs.com/page/520743/