GO单元测试 | 青训营笔记

135 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 7 天

测试一般分为,回归测试一般是QA同学手动通过终端回归一些固定的主流程场景,集成测试是对系统功能维度做测试验证(自动化通过某个服务暴露接口),而单元测试测试开发阶段,开发者对单独的函数、模块做功能验证,层级从上至下,测试成本逐渐减低,而测试覆盖率确逐步上升,所以单元测试的覆盖率一定程度上决定这代码的质量。

单元测试

image-20230216114905231.png

单测一方面可以保证质量,在整体覆盖率足够的情况下,一定程度上既保证了新功能本身的正确性,又未破坏原有代码的正确性。另一方面可以提升效率,在代码有bug的情况下,通过编写单测,可以在一个较短周期内定位和修复问题。

单测规则:

image-20230216115134233.png

单测例子:校对

image-20230216115432075.png

单测运行:也可以直接run

image-20230216115507734.png

单测-assert:用于校对中比较 .Equal/notEqual

image-20230216115544405.png

单测-覆盖率:

image-20230216133226530.png

运行代码同时测试覆盖率

66.7%:if语句和第一个true经过测试,return false为经过测试

image-20230216133526923.png

100% 覆盖率

对各分支测试方案,保证测试完备性

在实际项目中,一般的要求是50%~60%覆盖率(保证主流程没有问题),而对于资金型服务(支付、极限操作),覆盖率可能要求达到80%;我们做单元测试,测试分支完备,这样就比较简单的提升覆盖率,也符合函数设计的单一职责

image-20230216133843152.png

单测-依赖:

image-20230216134345030.png

上面三个依赖都是强依赖

幂等:每次运行这段代码结果一致

稳定:单元测试相互隔离,能在任何时间、环境,独立运行测试

直接写单元测试调到DB、Cache是不稳定的,需要依赖网络->用mock请求

单测-文件处理:

image-20230216153312528.png

下面举个栗子,将文件中的第一行字符串中的11替换成00,执行单测,测试通过,而我们的单测需要依赖本地的文件,如果文件被修改或者删除测试就会fail。为了保证测试case的稳定性,我们对读取文件函数进行mock,屏蔽对于文件的依赖。

Mock测试

(如果有web依赖,用mock实现,保证单元测试稳定性)

单测-Mock:

用到开源的mock包:monkey

image-20230216153621067.png

这里我们用了Monkey,monkey是一个开源的mock测试库,可以对method,或者实例的方法进行mock(打桩)

Patch 为一个函数打桩。参数target原函数,replacement打桩函数

Unpatch 打桩结束后把桩卸载下来

反射,指针赋值 Mockey Patch 的作用域在 Runtime(运行时),在运行时通过通过 Go 的 unsafe 包,能够将内存中函数的地址替换为运行时函数的地址。 最终调用打桩函数

下面是一个mock的使用样例,通过patch对Readfineline进行打桩mock,默认返回line110,这里通过defer卸载mock,这样整个测试函数就拜托了本地文件的束缚和依赖。

image-20230216154455449.png

不在->不再

基准测试

基准测试:

Go 语言还提供了基准测试框架,基准测试是指测试一段程序的运行性能耗费 CPU 的程度。而我们在实际项目开发中,经常会遇到代码性能瓶颈,为了定位问题经常要对代码做性能分析,这就用到了基准测试。使用方法类似于单元测试

基准测试-例子:服务器负载均衡-随机选择执行服务器

image-20230216155106016.png

测试函数BenchmarkXxx

image-20230216155446097.png

以上两种基准测试:

基准测试以Benchmark开头,入参是testing.B, 先初始化服务器列表,Resettimer重置计时器。因为initServerIndex不属于业务测试函数的符号,所以需要重置时间。

用b中的N值反复递增循环测试 (第一个是串行压力测试)(对一个测试用例的默认测试时间是 1 秒,当测试用例函数返回时还不到 1 秒,那么 testing.B 中的 N 值将按 1、2、5、10、20、50……递增,并以递增后的值重新进行用例函数测试。) Restetimer重置计时器,我们在reset之前做了init或其他的准备操作,这些操作不应该作为基准测试的范围。

runparallel是多协程并发测试

执行2个基准测试,最右侧是每次cpu耗时。发现代码在并发情况下存在劣化,主要原因是rand为了保证全局的随机性和并发安全,持有了一把全局锁。性能优化用fastrand函数。

fastrand牺牲了随机数的一致性换取性能,在高并发、多数场景推荐。