Unittest
小型测试带来优秀的代码质量、良好的异常处理、优雅的错误报告;大中型测试会带来整体产品质量和数据验证。
不同类型的项目,对测试的需求不同,总体上有一个经验法则,即 70/20/10
原则:70%
是小型测试,20%
是中型测试,10%
是大型测试。
如果一个项目是面向用户的,拥有较高的集成度,或者用户接口比较复杂,他们就应该有更多的中型和大型测试;如果是基础平台或者面向数据的项目,例如索引或网络爬虫,则最好有大量的小型测试,中型测试和大型测试的数量要求会少很多。
“自动化实现的,用于验证一个单独函数或独立功能模块的代码是否按照预期工作,着重于典型功能性问题、数据损坏、错误条件和大小差一错误(译注:大小差一(off-by-one
)错误是一类常见的程序设计错误)等方面的验证”
- 《Google软件测试之道》
单元测试的基本要求:
- 快速
- 环境一致
- 任意顺序
- 并行
基于 docker-compose
实现跨平台跨语言环境的容器依赖管理方案,以解决运行 unittest 场景下的(mysql, redis, mc)容器依赖问题:
- 本地安装 Docker。
- 无侵入式的环境初始化。
- 快速重置环境。
- 随时随地运行(不依赖外部服务)。
- 语义式 API 声明资源。
- 真实外部依赖,而非 in-process 模拟。
正确的对容器内服务进行健康检测,避免 unittest 启动时候资源还未 ready。
应该交由 app 自己来初始化数据,比如 db 的 scheme ,初始的 sql 数据等,为了满足测试的一致性,在每次结束后,都会销毁容器。
在单元测试开始前,导入封装好的 testing 库,方便启动和销毁容器。
对于 service 的单元测试,使用 gomock 等库把 dao mock 掉,所以在设计包的时候,应该面向抽象编程。
在本地执行依赖 Docker,在 CI 环境里执行 Unittest ,需要考虑在物理机里的 Docker 网络,或者在 Docker 里再次启动一个 Docker 。
利用 go 官方提供的: Subtests + Gomock 完成整个单元测试。
/api
比较适合进行集成测试,直接测试 API,使用 API 测试框架(例如: yapi),维护大量业务测试 case。
/data
docker compose 把底层基础设施真实模拟,因此可以去掉 infra 的抽象层。
/biz
依赖 repo、rpc client,利用 gomock 模拟 interface 的实现,来进行业务单元测试。
/service
依赖 biz 的实现,构建 biz 的实现类传入,进行单元测试。
基于 git branch 进行 feature 开发,本地进行 unittest,之后提交 gitlab merge request 进行 CI 的单元测试,基于 feature branch 进行构建,完成功能测试,之后合并 master,进行集成测试,上线后进行回归测试。