go 单元测试 testing 打印输出_2020,你需掌握go 单元测试进阶篇

51795e1b8e1645a0044423634f62e704.png

本文说明go语言自带的测试框架未提供或者未方便地提供的测试方案,主要是用于解决写单元测试中比较头痛的依赖问题。也就是伪造模式,经典的伪造模式有桩对象(stub),模拟对象(mock)和伪对象(fake)。比较幸运的是,社区有丰富的第三方测试框架支持支持。下面就对笔者亲身试用并实践到项目中的几个框架做介绍:

1.gomock

gomock模拟对象的方式是让用户声明一个接口,然后使用gomock提供的mockgen工具生成mock对象代码。要模拟(mock)被测试代码的依赖对象时候,即可使用mock出来的对象来模拟和记录依赖对象的各种行为:比如最常用的返回值,调用次数等等。文字叙述有点抽象,直接上代码:

e1aa7424defb715cee531e42542124a6.png

dick.go中DickFunc依赖外部对象OutterObj,本示例就是说明如何使用gomock框架控制所依赖的对象。

func DickFunc( outterObj MockInterface,para int)(result int){fmt.Println("This init DickFunc")fmt.Println("call outter.func:")return outterObj.OutterFunc(para)
}

mockgen工具命令是:

mockgen -source {source_file}.go -destination {dest_file}.go

比如,本示例即是:

mockgen -source src_mock.go -destination dst_mock.go

执行完后,可在同目录下找到生成的dst_mock.go文件,可以看到mockgen工具也实现了接口:

b2aa8488b26a4b4eb292ce7ec4c7866a.png

接下来就可以使用mockgen工具生成的NewMockInterFace来生产mock对象,使用这个mock对象。OutterFunc()这个函数,gomock在控制mock类时支持链式编程的方式,其原理和其他链式编程类似一直维持了一个Call对象,把需要控制的方法名,入参,出参,调用次数以及前置和后置动作等,最后使用反射来调用方法,所以这个Call对象是mock对象的代理。jmockit的早期版本也是jdk自带的java.reflect.Proxy动态代理实现的(最近的版本是动态Instrumentation配合代理模式)。

b7277448de5eed7b824f081c861e3873.png

在本示例中只简单的更改了返回值,抛砖引玉:

func TestDickFunc(t *testing.T ){mockCtrl := gomock.NewController(t)
//defer mockCtrl.Finish()mockObj := dick.NewMockMockInterface(mockCtrl)mockObj.EXPECT().OutterFunc(3).Return(10)result :=dick.DickFunc(mockObj,3)t.Log("resutl:",result)}

使用go test命令执行这个单测

12785898b884827c53264dbafa65a099.png

从结果看:本来应该输出3,最后输出就是10,和其他语言mock框架相似,生产出来的Mock对象不用自己去重定义这么麻烦。

2.httpexcept

由于go在网络架构上的优秀封装,使得go在很多网络场景被广泛使用,而http协议是其中重要部分,在面对http请求的时候,可以对http的client进行测试,算是mock的特殊应用场景。

看一个简单的示例就轻松的看懂了:

func TestHttp(t *testing.T) {handler := FruitServer()server := httptest.NewServer(handler)defer server.Close()e := httpexpect.New(t, server.URL)e.GET("/fruits").Expect().Status(http.StatusOK).JSON().Array().Empty()
}

其中还支持对不同方法(包括Header,Post等)的构造以及返回值Json的自定义

3.testify

还有一个testify使用起来可以说兼容了《一》中的gocheck和gomock,但是其mock使用稍微有点烦杂,使用继承tetify.Mock(匿名组合)重新实现需要Mock的接口,在这个接口里使用者自己使用Called(反射实现)被Mock的接口。

《单元测试的艺术》中认为stub和mock最大的区别就依赖对象是否和被测对象有交互,而从结果看就是桩对象不会使测试失败,它只是为被测对象提供依赖的对象,并不改变测试结果,而mock则会根据不同的交互测试要求,很可能会更改测试的结果。说了这么多理论,但其实这两种方法都不是割裂的,所以gomock框架除了像其名字一样可以模拟对象以外,还提供了桩对象的功能(stub)。以其实现来说,更像是一个桩对象的注入。但是因为兼容了多个有用的功能,所以其在社区最为火爆。

4.go-sqlmock

还有一种比较常见的场景就是和数据库的交互场景,go-sqlmock是sql模拟(Mock)驱动器,主要用于测试数据库的交互,go-sqlmock提供了完整的事务的执行测试框架,最新的版本(16.11.02)还支持prepare参数化提交和执行的Mock方案。

比如有这样的被测函数:

func recordStats(db *sql.DB, userID, productID int64) (err error) {tx, err := db.Begin()if err != nil {return}defer func() {switch err {case nil:err = tx.Commit()default:tx.Rollback()}}()if _, err = tx.Exec("UPDATE products SET views = views + 1"); err != nil {return}if _, err = tx.Exec("INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil {return}return
}func main() {db, err := sql.Open("mysql", "root@/root")if err != nil {panic(err)}defer db.Close()if err = recordStats(db, 1 , 5 ); err != nil {panic(err)}
}

单测时:

func TestShouldUpdateStats(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("mock error: '%s' ", err)}defer db.Close()mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectCommit()if err = recordStats(db, 2, 3); err != nil {t.Errorf("exe error: %s", err)}if err := mock.ExpectationsWereMet(); err != nil {t.Errorf("not implements: %s", err)}
}//测试回滚
func TestShouldRollbackStatUpdatesOnFailure(t *testing.T) {db, mock, err := sqlmock.New()if err != nil {t.Fatalf("mock error: '%s'", err)}defer db.Close()mock.ExpectBegin()mock.ExpectExec("UPDATE products").WillReturnResult(sqlmock.NewResult(1, 1))mock.ExpectExec("INSERT INTO product_viewers").WithArgs(2, 3).WillReturnError(fmt.Errorf("some error"))mock.ExpectRollback()// 执行被测方法,有错if err = recordStats(db, 2, 3); err == nil {t.Errorf("not error")}// 执行被测方法,mock对象if err := mock.ExpectationsWereMet(); err != nil {t.Errorf("not implements: %s", err)}
}

介绍了这么多框架,最后需要说明的也可能最重要的是写代码时就应该考虑代码是可被测试的。要使得单元测试容易写,或者说代码容易被测,其实很重要的一个部分就是被测代码本身是容易被测的,也就是说在设计和编写代码的时候就应该先想到相好如何单元测试,甚至有人提出可以先写单元测试,再写具体被测代码。因为一个接口(或者称为单元)在被设计好后,它实现就确定了,实际效果也确定了。这种方式被称作测试驱动开发(Test-Driven Development, TDD)。而对于已经写好的代码,很大程度上不好测试,有一种方式是测试性重构,就是为了更好的测试而进行重构。这些一定程度上来说比了解这些框架更重要。
以上内容就是本篇的全部内容以上内容希望对你有帮助,有被帮助到的朋友欢迎点赞,评论。
如果对软件测试、接口测试、自动化测试、面试经验交流。感兴趣可以关注我,我们会有同行一起技术交流哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一文读懂Git工作流

Git是目前最流行的代码管理工具,相信大家也都是在用Git来管理自己团队的源代码。 团队一般为了规范开发,保持良好的代码提交记录以及维护 Git 分支结构清晰,方便后续维护等,都会迫切需要一个比较规范的 Git 工作流。 本文就是在…

xbox360fsd更新游戏封面_游戏类短视频创作指南

一.起步阶段1.内容发布垂直,整体风格一致,选定一个品类的游戏内容风格持续更新注意:冷启动时期不要频繁更换游戏类型2.账号IP化 根据自身风格特色打造独特的风格账号。有利延长账号生命周期,提升粉丝转化率。搞笑、中二…

开发者们都在关注的网站

开发者们都在关注的网站 😉 综合类(5个) 1、GitHub 全球最大的编程开源社区,很多优秀的开源项目都在上边,不知道这个都不要说自己是程序员😂 访问地址:https://github.com 2、CSDN 全球最大中…

ios framework 调用第三方 framework_Python基础:标准库和常用的第三方库

Python的标准库有:名称作用datetime为日期和时间处理同时提供了简单和复杂的方法。zlib直接支持通用的数据打包和压缩格式:zlib,gzip,bz2,zipfile,以及 tarfile。random提供了生成随机数的工具。math为浮点…

作图神器ProcessOn - 免费好用

因工作需要,我经常需要花一些流程图,时序图,架构图什么的,之前使用的Windows系统,大部分情况下就用的Visio来画图。后来为了工作方便,换成了Mac电脑,结果发现Mac上没有Visio,然后就在…

三电平igbt死区时间计算_基于大功率三电平IGBT模块并联的参考设计

当前的可再生能源行业中,光伏和风力发电均面临着补贴逐步退坡,平价上网时代即将到来的挑战。为应对这一挑战,光伏逆变器和风力变流器厂家研发的新品单机功率越来越高,以取得更低的单位功率成本。市场上1.5MW的集中式光伏逆变器和3…

手把手教你搭建开发环境之Java开发

大家好呀,从今天开始,我们的手把手系列教程就正式开始啦。 如果你觉得本文对你有一些帮助,欢迎大家关注、点赞、分享给需要的小伙伴们,谢谢大家啦。 前言 Java虽然是一个比较老的语言,但到现在依然充满了活力&#x…

opc服务器组态文件已写保护_远程组态软件不仅方便了PLC无线远程监控,也大大降低了工程成本...

远程组态软件不仅方便了PLC无线远程监控,也大大降低了工程成本组态软件远程监控1.本地上位SCADA系统采集分布各地现场PLC等设备运行的数据,并可以下发控制指令;2.提供稳定的OPC接口服务,常年稳定运行,规模可达10万数据…

奇妙的安全旅行之加密算法概述

前言 hi,大家好呀,信息安全作为当前社会中比较重要的一个课题,已经覆盖了人们生活的方方面面,虽然有时候我们可能并没有意识到,其实信息安全防护已经在背后默默的保护我们的信息安全了。例如,当你在互联网…

怎么调节电机启动值_开关式智能充电机-全自动充电机-铅酸电池充电机品牌-济南能华...

开关式智能充电机-全自动充电机-铅酸电池充电机品牌-济南能华NHCD系列 全自动智能充电机,可调智能充电机,可调直流充电机,可调全自动充电机 ,可调蓄电池充电机 便携式可调智能充电机 便携式全自动充电机 大功率可调充电机 大功率智…

奇妙的安全旅行之MD算法

hi,大家好,今天我们开始介绍消息摘要算法中的MD(Message Digest)算法,MD算法家族包括:MD2,MD4,MD5,MD算法生成的消息摘长度要都是128位的。 其中MD5算法是消息摘要算法的…

的图层类型有哪些_东莞都市领航平面设计培训班都学习哪些内容?

平面设计的工作稳定性是很高的,经济繁荣时期毫无疑问,即使经济下滑,仍不会有很大影响,以前两年为例,北美的大规模裁员浪潮,给高科技行业带来巨大冲击,放慢了高科技产品的开发速度,当…

dockerfile拉取私库镜像_还在用Alpine作为你Docker的Python开发基础镜像?其实Ubuntu更好一点...

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_173一般情况下,当你想为你的Python开发环境选择一个基础镜像时,大多数人都会选择Alpine,为什么?因为它太小了,仅仅只有 5 MB 左右(对比 Ubuntu 系列镜像接…

2020,再见;2021,我来了!

现在是2021年1月16日下午16点33分,星期六。此时北京正在通报昨日新冠肺炎新增病例情况,这种每天戴口罩的鬼日子还不知道什么时候能结束。最近由于天气变冷,病毒更容易存活和传播,最近一个月就突然又变的非常紧张起来了&#xff0c…

cuda tensorflow版本对应_Windows10下安装tensorflow-gpu(2.2.0)安装教程(避坑+保姆式教学)...

本文实现了Windows10下GPU版本的tensorflow2.2.0的安装,用到的软件主要包括:CUDA 10.2 cuDNN Anaconda tensorflow-gpu 2.2.0。(注:此教程在Win7环境下也同样适用!另附报错缺少cudart64_101.dll的解决办法&#xff…

奇妙的安全旅行之DES算法(二)

hi,大家好,上一节我们详细介绍了对称加密算法DES的基本内容,由于明文的长度不固定,而加密算法只能处理特定长度的一块数据,所以就需要对比较长的明文进行分组后再加密,但是分组后,最后一组的长度…

c++创建虚拟串口_linux虚拟串口控制器驱动实现——适用于无开发板学习串口驱动...

在上一章我们已经说明了uart驱动的开发流程,本章我们就不再介绍uart相关的接口实现,仅通过实现一个虚拟的串口控制器程序,用以说明虚拟串口的开发流程。本次开发的虚拟串口提供的功能如下:提供两个串口实例串口名称的前缀为vttyU为…

奇妙的安全旅行之AES算法

hi,大家好,今天开始我们来介绍一下对称加密算法中的AES算法。 AES简介 AES(英语:Advanced Encryption Standard,缩写:AES),即高级加密标准,在密码学中又称Rijndael加密…

axios vue 回调函数_前端Vue 面试题大全

点蓝色字关注“程序员报刊” 「学习 新闻 招聘 」vue的底层原理?vue组件之间的通信?JS中判断数据类型的方法有几种?最常见的判断方法:typeof判断已知对象类型的方法:instanceof根据对象的constructor判断:constructor无敌万能的…

奇妙的安全旅行之RSA算法

hi,大家好,我是开发者FTD。今天我们开始介绍非对称加密算法。非对称加密算法区别于对称加密算法的主要特点是,非对称加密算法有两个密钥:公钥 (public key) 和私钥 (private key)。公钥和私钥是一对密钥,如果用公钥对数…