download:2022全面降级Vue3+TS 仿知乎专栏企业级我的项目

Golang-单元测试和模仿框架的介绍和举荐
简介:摸索golang的单元测试框架,看看哪个框架与业务教训联合得更好。
我会在题目中标注举荐帧和不举荐帧。如果没有标注,阐明体验个别,然而没有特地的毛病。我将刮目相待。
一、单元测试框架介绍
1.本地测试
1.1示例
func TestModifyArr(t *测试。T) {
arr := [3]int{0,1,2}
批改(Arr)
if 112233 == arr[0] {
T.logf ("[testmodifyar] test胜利批改了数组元素!")
} else if 0 == arr[0] {
T.errorf ("[testmodifyar] test未能批改数组元素!元素未修改”)
}否则{
T.errorf ("[testmodifyar] test未能批改数组元素!未知元素:%d ",arr[0])
}
}
复制代码
留神:在应用t.Errorf时,单个测试也会被设置为失败(然而测试不会立刻进行,只有FailedNow或Fatalf才会进行)
1.2扩大:表格驱动的设计思维
其实就是把多个测试用例封装成一个数组,顺次执行同一个测试逻辑。
即便是其余测试框架,这种设计思路也是相当有用的,用例多的时候能够简化代码量。
示例:
危险值(
pow tests =[]构造{
根底浮动64
电源浮动64
预期浮动64
}{
{1, 5, 1},
{2, 4, 16},
{3, 3, 27},
{5, 0, 1},
}
)

//测试一些数学包的计算方法
func testmathppkgmethodbytesting(t * testing。T) {
对于索引,以后测试:=范畴功率测试{
if currentTest.expected!=数学。Pow(以后测试基准,以后测试功率){
t.errorf("[TestMathPkgMethod]% d th test:%.2f % . 2f的幂不是预期的:% . 2f ",
index,currentTest.base,currentTest.power,currentTest.expected)
}
}
t.Logf("[TestMathPkgMethod]所有测试都通过了!")
}
复制代码
1.3平行测试
应用办法:在测试代码中执行:t.Parallel(),测试方法能够和其余测试用例并行执行。
场景:个别须要同时执行多个用例,比方测试生产和生产。
但集体不倡议这么做,因为这有点违反“繁多测试”的概念:繁多测试测试一个性能。相似的场景也能够通过在单次测量中设置通道多流程来实现。
2、goconvey
2.1示例
介绍办法:
去找github.com/smartystreets/goconvey/convey

导入模式:
导入(
。" github . com/smarty streets/go convey/convey "
)

//揭示:goconvey、gomonkey等工具类最好应用这种导入办法,缩小应用其外部办法的代码长度,使代码更加简洁。
复制代码
func TestMathPkgMethodByConvey(t *测试。T) {
Convey(" Convey test power ",t,func() {
对于_,以后测试:=范畴功率测试{
所以(数学。Pow(currentTest.base,currentTest.power),ShouldEqual,currentTest.expected)
}
})
}
复制代码
So的这种办法构造对于刚接触GoConvey的同学来说可能有点难以了解。上面是源代码的简要阐明:
//源代码:github . com \ smarty streets \ go convey @ v 1 . 6 . 4 \ convey \ context . go
类型断言函数(理论接口{},应为...接口{})字符串
......
func (ctx *context) So(理论接口{},assert断言,应为...接口{}) {
if result := assert(理论,预期...);result == assertionSuccess {
ctx.assertionReport(报告。NewSuccessReport())
}否则{
ctx.assertionReport(报告。NewFailureReport(后果))
}
}
复制代码
要害是对So参数的了解。总共有三个参数:
理论:输出
断言:断言
预期:预期值
通过查看定义,Assert assertion实际上是一种办法,但事实上,Convey包曾经帮忙咱们定义了大多数根本断言:
//源代码:github . com \ smarty streets \ go convey @ v 1 . 6 . 4 \ convey \ assertions . go
危险值(
ShouldEqual =断言。肩平等
ShouldNotEqual =断言。不应相等
ShouldAlmostEqual =断言。应该差不多相等
ShouldNotAlmostEqual =断言。ShouldNotAlmostEqual
should like =断言。应该像
ShouldNotResemble =断言。不应该类似
.....
复制代码
能够间接应用等于、大于或小于等判断办法。
2.2双重嵌套
func TestMathPkgMethodByConvey(t *测试。T) {
//双重嵌套
Convey("Convey test multiple test ",t,FailureHalts,func() {
Convey("测试失败",func() {
所以(数学。Pow(5,2),ShouldEqual,26)
日志。printf("[测试] 5^3 = 125?要执行!”)
所以(数学。Pow(5,3),ShouldEqual,125)
})

Convey("胜利测试",func() {
日志。printf("[测试] 5^2 = 25?要执行!”)
所以(数学。Pow(5,2),ShouldEqual,25)
})
})
}
复制代码
留神:不再须要将测试对象增加到传送带的内层。
留神:子传送的执行策略是并行的,因而前一个子传送的失败不会影响后续的传送。然而一个孩子被间断处决。
2.3跳过测试
如果在这次提交中有些测试没有被齐全测试,您能够应用TODO+首先跳过这些测试,首先进行正文,而后在下一次提交时改良它们。
SkipConvey:跳过以后考察下的所有测试。
SkipSo:跳过以后断言
2.4设置失败后的执行策略
默认状况下,一个Convey下的多个So断言是失败后终止的策略。如果要调整,只需将失败策略增加到Convey参数中即可。例如,如果设置失败,请持续,而后应用失败持续。
//源代码:github . com \ smarty streets \ go convey @ v 1 . 6 . 4 \ convey \ doc . go
常量(
......
失败持续失败模式= "持续"

......
故障暂停故障模式= "暂停"

......
失败继承失败模式= "继承"
)
复制代码
然而,应该留神,这里的故障后策略是针对一个传送下的多个So断言,而不是一个传送下的多个子传送。那么接下来咱们就来说说Convey的实现机制:它是并行的。
2.5子传送并发执行原理简介
在go transportation的底层,应用jtolds/gls库实现对goroutine的治理和多个子传输的并发执行。
//源代码:github . com \ smarty streets \ go convey @ v 1 . 6 . 4 \ convey \ context . go
func (ctx *context)传送(我的项目...接口{}) {
......

if inner_ctx.shouldVisit() {
ctxMgr。设置值(gls。值{nodeKey: inner_ctx},func() {
//条目。Func是理论的测试方法。
inner _ ctx.conveyInner(条目。状况,进入。Func)
})
}
}

//源代码:github . com \ jtolds \ gls @ v 4 . 20 . 0+不兼容\context.go
func(m * context manager)set Values(new _ Values Values,context_call func()) {
......

//此办法将确定是否满足并发执行的条件。
EnsureGoroutineId(func(GID uint){
.......//解析传入的上下文参数。

context_call()
})
}
复制代码
常识无限,这里就不说gls库的原理了。借助一些文档,我晓得gls其实是通过go底层的api来治理GPM模型的,在满足肯定条件的状况下,会将子考察提交给子协同流程执行(默认)。
如果你对gls库感兴趣,想晓得它的底层是如何治理合作流程的,能够参考:
Gl官网github地址
gls godoc
3.作证(举荐)
其实evidence的用法和native testing差不多,都是对断言的明确定义。
它提供了assert和require两种用法,别离对应失败后的执行策略。前者失败后继续执行,后者失败后立刻进行。但都是单断言失败,以后测试失败。
func TestGetStudentById(t * testing。T) {
currentMock := gomonkey。ApplyFunc(dbresource。NewDBController,dbresource。NewDBMockController)
推延以后时钟。重置()
学校服务。新学校服务()
学生:=学校服务。GetStudentById("1 ")

断言。NotEqual(t,“”,学生。姓名)
要求。Equal(t,studentsql。考试_学生_姓名,学生。姓名)
}
复制代码
4.测试框架概述
上面简略总结一下几个测试框架:集体感觉GoConvey的语法对于业务代码入侵来说有点重大,自身须要一些工夫去了解,比方testify的清晰逻辑。单元测试逻辑自身绝对简略。综上,更举荐应用evident。
二。模仿框架介绍
1.gostub(不举荐)
1.1根本用处
去找github.com/prashantv/gostub
复制代码
func TestGetLocalIp(t *测试。T) {
//沉积变量
varStub := Stub(&testGlobalInt,100)
提早变量存根。重置()
日志。printf("[测试模仿]模仿变量:%d ",testGlobalInt)

//沉积办法
var getIpFunc = system。GetOutboundIP
funcStub := StubFunc(&getIpFunc," 1.2.3.4 ")
提早funcStub。重置()
}
复制代码
1.2与GoConvey组合的示例

1.3不举荐应用的起因
次要的限度太多了:
Gostub:因为办法的mock要先申明变量能力被mock,所以连贯口办法都须要这样定义,不是很不便。
此外,如果您须要一个mock办法,并且参数和返回的数量是可变长度的数组类型,您可能无奈定义mock。
最初,同样的办法,如果须要模仿多个场景,gostub无奈实现。这个很麻烦,mock的不同参数场景应该算是mock的基本功能。
2、gomock
官网保护的mock框架,只有是对象+接口的数据结构,根本都能够通过gomock间接写不同场景的mock。
之前写过一篇对于如何应用gomock的根底介绍。一般来说更适宜框架场景,比方protobuf定义生成的内部对象和接口。如果能主动生成gomock代码,开发起来会更不便。但不是特地适宜业务代码,因为业务外部往往定义了很多对象,为每个对象生成mock有点麻烦。

3.1打桩办法
func TestGetAbsolutePath(t *测试。T) {
//打桩办法
funcStub := ApplyFunc(config。GetAbsolutePath,testGetAbsolutePath)
提早funcStub。重置()
日志。Printf("配置门路:%s ",config。GetAbsolutePath())
}
复制代码
总的来说和gostub的应用很像,就是办法要通过变量独自指定,mock要设置。执行ApplyFunc办法
区别在于StubFunc间接定义方法的参数(行为后果),而ApplyFunc还须要定义方法的具体动作(行为自身)。
3.2用程序堆法。
func TestGetAbsolutePath(t *测试。T) {
//办法序列重叠
retArr:=[]输入单元格{
{Values: Params{"。/testpath1"}},
{Values: Params{"。/testpath2"}},
{Values: Params{"。/testpath3"},次数:2,
}
ApplyFuncSeq(配置。GetAbsolutePath,retArr)

日志。Printf("配置门路:%s ",config。GetAbsolutePath())
日志。Printf("配置门路:%s ",config。GetAbsolutePath())
日志。Printf("配置门路:%s ",config。GetAbsolutePath())
日志。Printf("配置门路:%s ",config。GetAbsolutePath())
}
复制代码
3.3全局变量的打桩

用法相似于gostub的Stub办法,不赘述。
此外,还有ApplyMethod(为对象的指定办法打桩)、ApplyMethodSeq等。,而且用法还是很像ApplyFunc的。您能够具体浏览参考博客,或者只查看源代码中的测试示例。
四。总结与瞻望
介绍了几种常见的单测和mock框架的应用办法,得出了evidence+gomonkey是一种比拟直观易用的框架的论断。