Ginkgo&Gomega
前言
最近公司项目实现标准化,打算给项目加上单元测试和集成测试,在Go的项目中由调研后打算采用Ginkgo和Gomega,看了下官方文档和github上的测试后写下点心得
Ginkgo是Go语言的一个行为驱动开发(BDD)风格的测试框架,通常和Gomega一起使用
Gomega是一个匹配/断言库,通常与Ginkgo测试框架搭配使用
下面的文章对上面的文档进行了参考和引用
对于测试的方法和使用请参考具体的文档,本文章主要介绍实战的使用
安装
安装Ginkgo
1  |  | 
安装Gomega
1  |  | 
开始
Ginkgo与Go自带测试挂钩,允许使用go test运行Ginkgo套件
创建套件
如果要为一个包编写Ginkgo测试,首先需要使用命令创建套件
1  |  | 
上诉命令会生成文件:
1  |  | 
创建完成后就可以在当前包下使用ginkgo或者go test执行测试套件
添加Spec
上面的空测试套件没有什么价值,我们需要在此套接下编写测试(Spec)。虽然可以在books_suite_test.go中编写测试,但是推荐分离到独立的文件中,特别是包中有多个需要被测试的源文件的情况下
1  |  | 
1  |  | 
Describe块用来组织Specs,其中可以包含任意数量的It:可以在Describe、Context这两种容器块内编写Spec,每个Spec写在It块中;为了贴合自然语言,可以使用It的别名Specify- 使用
Describe和Context来标识组织代码的具体行为 BeforeEach:在Spec(It块)运行之前执行,嵌套Describe时最外层BeforeEach先执行AfterEach:在Spec运行之后执行,嵌套Describe时最内层AfterEach先执行JustBeforeEach:在It块,所有BeforeEach之后执行,在It之前运行
实战
现在要对网页后端的多个API接口进行集成测试
初步
1  |  | 
- 上诉的思想就是每个测试组件都提前定义好
request和response,通过发送给client的request加上Gomega断言收到的response来进行测试 - 把每个测试组件都要使用的变脸,如
url、method、client等放最初的全局变量 - 每次使用前都要重新初始化
client、request、response则放入BeforeEach(如果使用了response.Body)可以使用AfterEach进行关闭 
对上面不同的Gomega断言类型进行说明
gomega.Expect(res.StatusCode).Should(gomega.Equal(http.StatusOK))Should和To相同,表示肯定,gomega.Equal则是表示断言相等,连起来就是我们实际得到的res.StatusCode应该和http.StatusOK相同,相同测试成功,不同测试失败gomega.Expect(err).ShouldNot(gomega.HaveOccurred())ShouldNot和NotTo相同,表示否定,gomega.HaveOccurred()指示non-nill的error则成功,连起来就是如果出现non-nil的error就测试失败,error为nil则测试成功,则是非常典型的Go错误测试模式gomega.Expect(res).To(test.RepresentJSONObject(http.StatusOK))自定义匹配规则,只要实现
Match、FailureMessage、NegatedFailureMessage方法的接口就行,好处就是匹配规则灵活多变(传入的http.StatusOK作为expected去Match Expect中的 res),匹配结果返回的是false和non-err则为测试失败
1  |  | 
改进
1  |  | 
1  |  | 
采用自定义封装匹配规则和
gomega.HaveOccurred()错误断言对变量定义和初始化进行封装,因为每次在调用后都要重新初始化
TCli,所以采用创建套件时初始化TCli和每次It结束后初始化的方法1
2
3
4//在ginkgo bootstrap创建套件的文件中,表示启动测试套件的每一个总Describe运行前都要执行的代码
var _ = BeforeSuite(func() {
warpper.InitTCli()
})对
BeforeEach中client发送request和接收response的代码进行封装1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16func (t *TeClient) Do(method, url, reqJson string) error {
adr := "http://" + ip + url
t.Req, t.Err = http.NewRequest(method, adr, strings.NewReader(reqJson))
t.Req.Header.Add("xxx", "xxx")
t.Req.Header.Add("xxx", "xxx")
if reqJson != "" {
t.Req.Header.Add("Content-Type", "application/json")
}
t.Res, t.Err = t.Client.Do(t.Req)
if t.Err != nil {
err := t.Err
return err
}
return nil
}把测试组件相同的代码抽出成函数调用的方式,这样测试组件中的代码简介明了
Header.Add(“xxx”,"xxx")一般都是token、安全验证,因为在测试中使用的身份是一样的对于有传如
request.Body的POST方法才加Header.Add("Content-Type", "application/json"),GET中不需要传入request.Body就不需要了
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!