Go Convey测试框架入门(go convey gomonkey)

2024-08-24 07:12

本文主要是介绍Go Convey测试框架入门(go convey gomonkey),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Go Convey测试框架入门

介绍

GoConvey是一款针对Golang的测试框架,可以管理和运行测试用例,同时提供了丰富的断言函数,并支持很多 Web 界面特性。
Golang虽然自带了单元测试功能,并且在GoConvey框架诞生之前也出现了许多第三方测试框架,但没有一个测试框架像GoConvey一样能够让程序员如此简洁优雅的编写测试代码。

官网:http://smartystreets.github.io/goconvey/

安装

go get 方式安装(go path时代,关闭go mod)

//下载源码并执行go build
//源码下载到$GOPATH/src目录
//go build之后的结果到$GOPATH/bin
go get github.com/smartystreets/goconvey

在$GOPATH/src目录下新增了github.com子目录,该子目录里包含了GoConvey框架的库代码 在$GOPATH/bin目录下新增了GoConvey框架的可执行程序goconvey

go install方式(开启go mod)

在gomod时代一般不需要先显式安装(gomod机制会自动从goproxy拉取依赖到本地cache),只需要go.mod中引入,然后go mod tidy即可。除非要使用GoConvey的web界面,这时需要提前安装GoConvey的二进制,命令为go install github.com/smartystreets/goconvey@latest。

go.mod:

module ziyi.convey.comgo 1.19require github.com/smartystreets/goconvey v1.8.1require (github.com/gopherjs/gopherjs v1.17.2 // indirectgithub.com/jtolds/gls v4.20.0+incompatible // indirectgithub.com/smarty/assertions v1.15.0 // indirect
)
//我后面要演示web页面,因此这里显示安装一下
//安装之后,依然会将编译好的二进制放在$GOPATH/bin
go install github.com/smartystreets/goconvey@latest

我的GOPATH为E:\Go\GoPro:
在这里插入图片描述

使用

注意事项

  1. import goconvey包时,前面加点号".",以减少冗余的代码。凡是在测试代码中看到Convey和So两个方法,肯定是convey包的。我们需要注意不要在产品代码中定义相同的函数名
  2. 测试函数的名字必须以Test开头,而且参数类型必须为*testing.T
  3. 每个测试用例必须使用Convey函数包裹起来,它的第一个参数为string类型的测试描述,第二个参数为测试函数的入参(类型为*testing.T),第三个参数为不接收任何参数也不返回任何值的函数(习惯使用闭包)
  4. Convey函数的第三个参数闭包的实现中通过So函数完成断言判断,它的第一个参数为实际值,第二个参数为断言函数变量,第三个参数或者没有(当第二个参数为类ShouldBeTrue形式的函数变量)或者有(当第二个函数为类ShouldEqual形式的函数变量)

案例一:1个测试用例1个Convey

c_test.go:

package mainimport (. "github.com/smartystreets/goconvey/convey""testing"
)func TestEqualWithSingleTestCase(t *testing.T) {// test name:用例名称// t:需要传入*testing.T// func(){} 测试函数Convey("test name", t, func() {//1+1:断言//ShouldEqual:convey内置的断言//2:期望结果So(1+1, ShouldEqual, 2)})
}

在这里插入图片描述

案例二:多个Convey多个测试用例

①平铺写法

func TestEqualWithMultipleTestCase(t *testing.T) {Convey("test add case", t, func() {So(1+1, ShouldEqual, 2)})Convey("test sub case", t, func() {So(1-1, ShouldEqual, 0)})Convey("test multi case", t, func() {So(1*1, ShouldNotEqual, -1)})
}

②Convey嵌套写法

只需要最外层的Convey传t *testing.T即可

func TestEqualWithMultipleTestCaseAndNested(t *testing.T) {Convey("test case", t, func() {Convey("test add case", func() {So(1+1, ShouldEqual, 2)})Convey("test sub case", func() {So(1-1, ShouldEqual, 0)})Convey("test multi case", func() {So(1*1, ShouldNotEqual, -1)})})
}

案例三:"函数式"断言(assert传入函数)

// 案例三:函数式断言
func TestFunctionalAssertion(t *testing.T) {Convey("test case", t, func() {So(add(1, 1), ShouldEqual, 2)})
}func add(a, b int) int {return a + b
}

案例四:忽略部分Convey断言

针对想忽略但又不想删掉或注释掉某些断言操作,GoConvey提供了Convey/So的Skip方法:

  • SkipConvey函数表明相应的闭包函数将不被执行
  • SkipSo函数表明相应的断言将不被执行

当存在SkipConvey或SkipSo时,测试日志中会显式打上"skipped"形式的标记:

当测试代码中存在SkipConvey时,相应闭包函数中不管是否为SkipSo,都将被忽略。
不管存在SkipConvey还是SkipSo时,测试日志中都有字符串"{n} total assertions (one or more sections skipped)",其中{n}表示测试中实际已运行的断言语句数

// 案例四:忽略Convey断言
//忽略所有断言
func TestCaseSkipConvey(t *testing.T) {SkipConvey("test case", t, func() {So(add(1, 1), ShouldEqual, 2)})
}//忽略某些断言(SkipSo的断言将被忽略)
func TestCaseSkipSo(t *testing.T) {Convey("test case", t, func() {SkipSo(add(1, 1), ShouldEqual, 2)So(1-1, ShouldEqual, 0)})
}

比如我执行TestCaseSkipSo函数:
在这里插入图片描述

案例五:定制断言函数

①原理分析

  1. 查看So源码
func So(actual interface{}, assert Assertion, expected ...any)

在这里插入图片描述
2. 点击查看Assertion结构体

type Assertion func(actual any, expected ...any) string

当Assertion的变量的返回值为""时表示断言成功,否则表示失败:

const assertionSuccess = ""

在这里插入图片描述
3. 结论
因此我们只需要按照结构,实现func,最后返回空串代表断言成功,否则失败

②实际操作

从上面的分析我们可以知道,当Assertion最后返回""代表断言成功,反之失败

// 案例五:定制断言
func TestCustomAssertion(t *testing.T) {Convey("test custom assert", t, func() {So(1+1, CustomAssertionWithRaiseMoney, 2)})
}func CustomAssertionWithRaiseMoney(actual any, expected ...any) string {if actual == expected[0] {return ""} else {return "doesn't raise money"}
}

案例六:访问web页面

如果要访问web页面,需要有goconvey.exe程序并运行,同时需要将xxx_test.go文件放在与exe同目录,否则无法识别到

  • go get “github.com/smartystreets/goconvey”
  • go install “github.com/smartystreets/goconvey” (如果开启了go mod,则用该方式)

默认安装到$GOPATH/bin目录下

执行exe后,访问本地localhost:8080端口即可看到web页面,页面展示的了单测的通过情况等。
在这里插入图片描述

拓展:gomonkey(打桩工具)

如果在被测函数中调用了其他函数(比如其他业务方的),可以使用以下方法,gomonkey打桩工具

  • 官网:https://github.com/agiledragon/gomonkey
//安装依赖
go get "github.com/agiledragon/gomonkey"

给全局变量打桩

使用 gomonkey 可以方便地模拟函数的行为


// 拓展:配合monkey打桩
var num = 10 //全局变量func TestApplyGlobalVar(t *testing.T) {Convey("TestApplyGlobalVar", t, func() {Convey("change", func() {//模拟函数行为,给全局变量复制,在函数结束后直接通过reset恢复全局变量值patches := gomonkey.ApplyGlobalVar(&num, 150)defer patches.Reset()So(num, ShouldEqual, 150)})Convey("recover", func() {So(num, ShouldEqual, 10)})})
}

给函数打桩

//对函数进行打桩
func TestFunc(t *testing.T) {// mock 了 networkCompute(),返回了计算结果2patches := gomonkey.ApplyFunc(networkCompute, func(a, b int) (int, error) {return 2, nil})defer patches.Reset()sum, err := Compute(1, 2)println("expected %v, got %v", 2, sum)if sum != 2 || err != nil {t.Errorf("expected %v, got %v", 2, sum)}
}func networkCompute(a, b int) (int, error) {// do something in remote computerc := a + breturn c, nil
}func Compute(a, b int) (int, error) {sum, err := networkCompute(a, b)return sum, err
}

全部代码:

欢迎大家star在这里插入图片描述

  • Github:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-convey
    在这里插入图片描述

c_test.go:

package mainimport ("github.com/agiledragon/gomonkey"_ "github.com/agiledragon/gomonkey". "github.com/smartystreets/goconvey/convey""testing"
)// 案例一:一个Convey,一个用例
func TestEqualWithSingleTestCase(t *testing.T) {// test name:用例名称// t:需要传入*testing.T// func(){} 测试函数Convey("test name", t, func() {//1+1:断言//ShouldEqual:convey内置的断言//2:期望结果So(1+1, ShouldEqual, 2)})
}// 案例二:多个Convey,多个用例(平铺写法)
func TestEqualWithMultipleTestCase(t *testing.T) {Convey("test add case", t, func() {So(1+1, ShouldEqual, 2)})Convey("test sub case", t, func() {So(1-1, ShouldEqual, 0)})Convey("test multi case", t, func() {So(1*1, ShouldNotEqual, -1)})
}// 案例二:多个Convey,多个用例(嵌套写法)
func TestEqualWithMultipleTestCaseAndNested(t *testing.T) {Convey("test case", t, func() {Convey("test add case", func() {So(1+1, ShouldEqual, 2)})Convey("test sub case", func() {So(1-1, ShouldEqual, 0)})Convey("test multi case", func() {So(1*1, ShouldNotEqual, -1)})})
}// 案例三:函数式断言
func TestFunctionalAssertion(t *testing.T) {Convey("test case", t, func() {So(add(1, 1), ShouldEqual, 2)})
}func add(a, b int) int {return a + b
}// 案例四:忽略Convey断言
// 忽略所有断言
func TestCaseSkipConvey(t *testing.T) {SkipConvey("test case", t, func() {So(add(1, 1), ShouldEqual, 2)})
}// 忽略某些断言(SkipSo的断言将被忽略)
func TestCaseSkipSo(t *testing.T) {Convey("test case", t, func() {SkipSo(add(1, 1), ShouldEqual, 2)So(1-1, ShouldEqual, 0)})
}// 案例五:定制断言
func TestCustomAssertion(t *testing.T) {Convey("test custom assert", t, func() {So(1+1, CustomAssertionWithRaiseMoney, 2)})
}func CustomAssertionWithRaiseMoney(actual any, expected ...any) string {if actual == expected[0] {return ""} else {return "doesn't raise money"}
}// 拓展:配合monkey打桩
var num = 10 //全局变量func TestApplyGlobalVar(t *testing.T) {Convey("TestApplyGlobalVar", t, func() {Convey("change", func() {//模拟函数行为,给全局变量复制,在函数结束后直接通过reset恢复全局变量值patches := gomonkey.ApplyGlobalVar(&num, 150)defer patches.Reset()So(num, ShouldEqual, 150)})Convey("recover", func() {So(num, ShouldEqual, 10)})})
}// 对函数进行打桩
func TestFunc(t *testing.T) {// mock 了 networkCompute(),返回了计算结果2patches := gomonkey.ApplyFunc(networkCompute, func(a, b int) (int, error) {return 2, nil})defer patches.Reset()sum, err := Compute(1, 2)println("expected %v, got %v", 2, sum)if sum != 2 || err != nil {t.Errorf("expected %v, got %v", 2, sum)}
}func networkCompute(a, b int) (int, error) {// do something in remote computerc := a + breturn c, nil
}func Compute(a, b int) (int, error) {sum, err := networkCompute(a, b)return sum, err
}

go.mod:

module ziyi.convey.comgo 1.19require (github.com/agiledragon/gomonkey v2.0.2+incompatiblegithub.com/smartystreets/goconvey v1.8.1
)require (github.com/gopherjs/gopherjs v1.17.2 // indirectgithub.com/jtolds/gls v4.20.0+incompatible // indirectgithub.com/smarty/assertions v1.15.0 // indirect
)

参考文章:
http://smartystreets.github.io/goconvey/
https://www.jianshu.com/p/e3b2b1194830

这篇关于Go Convey测试框架入门(go convey gomonkey)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1101805

相关文章

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Go路由注册方法详解

《Go路由注册方法详解》Go语言中,http.NewServeMux()和http.HandleFunc()是两种不同的路由注册方式,前者创建独立的ServeMux实例,适合模块化和分层路由,灵活性高... 目录Go路由注册方法1. 路由注册的方式2. 路由器的独立性3. 灵活性4. 启动服务器的方式5.

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

修改若依框架Token的过期时间问题

《修改若依框架Token的过期时间问题》本文介绍了如何修改若依框架中Token的过期时间,通过修改`application.yml`文件中的配置来实现,默认单位为分钟,希望此经验对大家有所帮助,也欢迎... 目录修改若依框架Token的过期时间修改Token的过期时间关闭Token的过期时js间总结修改若依

Go Mongox轻松实现MongoDB的时间字段自动填充

《GoMongox轻松实现MongoDB的时间字段自动填充》这篇文章主要为大家详细介绍了Go语言如何使用mongox库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码,需要的可以... 目录前言时间字段填充规则Mongox 的安装使用 Mongox 进行插入操作使用 Mongox 进行更

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ