单元测试
1. 什么是单元测试
单元测试在我们开发中是一个必不可少的一个环节,这里的单元其实指的是应用的最小可测试的部件,例如在过程化编程中,一个单元就是单个的程序、函数、过程等等,在面向对象编程中,最小单元指的就是方法、基类、超类、抽象类等中的方法。单元测试就是软件开发中对最小单位镜像正确性校验的测试工作,这个工作常常由开发人员进行编写与维护。
2.意义
- 提高代码质量。代码测试都是为了帮助开发人员发现问题从而解决问题,提高代码质量。
- 尽早发现问题。问题越早发现,解决的难度和成本就越低。
- 保证重构正确性。随着功能的增加,重构(修改老代码)几乎是无法避免的。很多时候我们不敢重构的原因,就是担心其它模块因为依赖它而不工作。有了单元测试,只要在改完代码后运行一下单测就知道改动对整个系统的影响了,从而可以让我们放心的重构代码。
- 简化调试过程。单元测试让我们可以轻松地知道是哪一部分代码出了问题。
- 简化集成过程。由于各个单元已经被测试,在集成过程中进行的后续测试会更加容易。
- 优化代码设计。编写测试用例会迫使开发人员仔细思考代码的设计和必须完成的工作,有利于开发人员加深对代码功能的理解,从而形成更合理的设计和结构。
- 单元测试是最好的文档。单元测试覆盖了接口的所有使用方法,是最好的示例代码。而真正的文档包括注释很有可能和代码不同步,并且看不懂。
golang中的一些实践
1. 表格驱动测试
所谓表格驱动测试其实就是将我们的测试用例与测试程序镜像分离,将测试用例放在一个数组中,下面写一个简单的案例
SliceDelStr功能是删除slice中的s item
1 | func SliceDelStr(slice []string, s string) []string { |
他对应的表格驱动unit test如下
1 | func TestSliceDelStr(t *testing.T) { |
看起来还是蛮简单的,基本所有的单元测试都可以套用此方法,能够比较清晰的区分不同case。但是这些也是一些比较理想的情况(属于工具类的方法,这类方法不存在外部依赖),但是我们能够发现,通常的代码逻辑中会场出现一些外部依赖(依赖外部服务),当出现这类服务要怎么优雅的编写ut呢?
其实也大概分为两类:
- 方法内部依赖底层服务,而这个服务是以interface提供出来
- 依赖外部远程调用服务,比如可能是一些SDK提供远程调用的能力,并且这些SDK没有做很好的接口抽象
对于这两种情况,有两种处理方法
2. 接口mock
服务中如果出现interface相关的依赖可以使用gomock一键生成mock数据,下面是个简单的例子
1 | package main |
在上面的例子中,我们使用了gomock的NewController
函数来创建一个新的Controller,这是gomock的核心概念之一。Controller用于管理所有mock对象,它可以确保mock对象的行为都按照我们的预期来执行,并在测试结束时检查所有预期是否都被满足了。然后,我们使用NewMockUserRepository
函数来创建一个mock UserRepository,它是通过go generate
命令生成的。我们可以使用这个mock UserRepository来模拟数据库操作。接着,我们使用EXPECT
函数来定义mock UserRepository的行为。在本例中,我们定义了mock UserRepository的FindUserByID
方法应该返回一个ID为1、名字为”Alice”的User对象。最后,我们创建了一个UserService,并注入mock UserRepository。然后,我们调用GetUserByID
方法,并使用if
语句来断言结果是否符合预期。
结合表格驱动测试
1 | func TestUserService_GetUserByID(t *testing.T) { |
- Post title: golang unit test的一些实践
- Create time: 2023-04-04 10:51:41
- Post link: post/9c1f9ce0.html
- Copyright notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.