针对如何有效测试Go码,阐述了单元测试,并针对两大难点:去耦、依赖,提出了面向接口、mock依赖的解决方案。 此外,本文还讨论了Go领域的实用测试工具,欢迎读者阅读。

单元测试的重点是代码逻辑单元,一般是对象或具体的函数。 我们可以编写足够的单元测试来确保代码的质量,在修改功能和代码重构时,足够的单元测试用例可以给我们足够的信心。

单元测试上面有开发规格。 敏捷软件开发有两个常客:测试驱动开发(Test-Driven Development,TDD )和行为驱动开发(Behavior-driven development,BDD )。 它们既是实践和技术,又是设计方法论。

TDD TDD的基本思想是通过测试推动整个开发,原则上在开发功能代码之前编写单元测试用例。 包括以下五个步骤。

开发人员首先写测试用例

运行这些测试,但这些测试显然会失败,因为测试用例的业务逻辑还没有实现

实现代码详细信息

如果开发人员成功实现代码,他们将执行并通过所有测试

及时重构业务代码,如果新代码的功能不正确,相应的测试文件也会失败

如果需要开发新功能,请重复上述步骤。 流程图如下图所示

tdd-flowchart有一个名为learn-Go-with-tests的Github仓库,目的是通过go学习TDD。

BDD TDD侧重于开发,通过测试用例规范地约束开发者编写更高质量、更少bug的代码。 BDD侧重于设计,在设计测试用例时提倡定义系统,用通用语言描述系统行为,推动系统设计与测试用例相结合进行开发工作。

BDD从TDD派生,主要区别在于测试的描述。 BDD用更易懂的文字编写测试用例,关注的是需求的功能,而不是实际的结果。

像读BDD给定的句子一样读测试的能力带来对测试认知的转变,对我们如何更容易写测试有帮助。

GinkGo Ginkgo是一个go语言的BDD测试框架,旨在帮助开发人员创建具有表现力的全面测试。

GinkGo集成了go本机测试库。 这意味着您可以在go test中运行Ginkgo测试套件。 它还与断言、mock工具包testify和富测试集go-check兼容。 但是,Ginkgo建议与gomega库一起使用。

下面,让我们使用Ginkgo感受BDD模式的测试代码。

使用go get获取的下载

$ gogetgithub.com/onsi/ginkgo/ginkgo $ gogetgithub.com/onsi/go mega/.此命令用于获取ginkgo,并将ginkgo可执行文件转换为$ ggggo

创建套件以创建gopher库

$cdpath-to-package/Gopher在gopher.go文件中提供了gopher结构和验证方法Validate

packagegopherimport (errors (unicode/utf8 ) ) typegopherstruct { namestringgenderstringageint } func validate ) ggopher='。 IFG.age18 ) {returnerrors.New年龄太小,18 ) }returnnil} )我们通过ginkgo bootstrap命令

$ ginkgobootstrapgeneratinginkgotestsuitebootstrapforgopherin : gopher _ suite _ test.go此时在gopher.go类目录中

package gopher _ test import (' testing '.' github.com/onsi/go mega '.' github.com/onsi/go mega ' ) functeststgophop 也可以是命令go test或ginkgo。

$ gotestrunningsuite : gopher suite===================gotestrunningsuite 3360 gopher suite========================gotestestestestestttt

=======Random Seed: 1629621653Will run 0 of 0 specsRan 0 of 0 Specs in 0.000 secondsSUCCESS! -- 0 Passed | 0 Failed | 0 Pending | 0 SkippedPASSok      ginkgo/gopher   0.018s

当然,空测试套件没有什么价值,我们需要在此套件下编写测试(Spec)用例。

我们可以在 gopher_suite_test.go 中编写测试,但是推荐分离到独立的文件中,特别是包中有多个需要被测试的源文件的情况下。

创建 Spec

执行 ginkgo generate gopher  可以生成一个 gopher_test.go 测试文件。

 $ ginkgo generate gopherGenerating ginkgo test for Gopher in:  gopher_test.go

此时测试文件中的内容如下

package gopher_testimport ( . "github.com/onsi/ginkgo")var _ = Describe("Gopher", func() {}) 编写 Spec

我们基于此测试文件撰写实际的测试用例

package gopher_testimport ( "ginkgo/gopher" . "github.com/onsi/ginkgo" "github.com/onsi/gomega")func mockInputData() ([]gopher.Gopher, error) { inputData := []gopher.Gopher{  {   Name:   "菜刀",   Gender: "男",   Age:    18,  },  {   Name:   "小西瓜",   Gender: "女",   Age:    19,  },  {   Name:   "机器铃砍菜刀",   Gender: "男",   Age:    17,  },  {   Name:   "小菜刀",   Gender: "男",   Age:    20,  }, } return inputData, nil}var _ = Describe("Gopher", func() { BeforeEach(func() {  By("当测试不通过时,我会在这里打印一个消息 【BeforeEach】") }) inputData, err := mockInputData() Describe("校验输入数据", func() {  Context("当获取数据没有错误发生时", func() {   It("它应该是接收数据成功了的", func() {    gomega.Expect(err).Should(gomega.BeNil())   })  })  Context("当获取的数据校验失败时", func() {   It("当数据校验返回错误为:名字太短,不能小于3 时", func() {    gomega.Expect(gopher.Validate(inputData[0])).Should(gomega.MatchError("名字太短,不能小于3"))   })   It("当数据校验返回错误为:只要男的 时", func() {    gomega.Expect(gopher.Validate(inputData[1])).Should(gomega.MatchError("只要男的"))   })   It("当数据校验返回错误为:岁数太小,不能小于18 时", func() {    gomega.Expect(gopher.Validate(inputData[2])).Should(gomega.MatchError("岁数太小,不能小于18"))   })  })  Context("当获取的数据校验成功时", func() {   It("通过了数据校验", func() {    gomega.Expect(gopher.Validate(inputData[3])).Should(gomega.BeNil())   })  }) }) AfterEach(func() {  By("当测试不通过时,我会在这里打印一个消息 【AfterEach】") })})

可以看到,BDD 风格的测试案例在代码中就被描述地非常清晰。由于我们的测试用例与预期相符,执行 go test 执行测试套件会校验通过。

 $ go testRunning Suite: Gopher Suite===========================Random Seed: 1629625854Will run 5 of 5 specs•••••Ran 5 of 5 Specs in 0.000 secondsSUCCESS! -- 5 Passed | 0 Failed | 0 Pending | 0 SkippedPASSok      ginkgo/gopher   0.013s

读者可自行更改数据致测试不通过,你会看到 Ginkgo 将打印出堆栈与错误描述性信息。

总结

TDD 和 BDD 是敏捷开发中常被提到的方法论。与TDD相比,BDD 通过编写 行为和规范 来驱动软件开发。这些行为和规范在代码中体现于更 ”繁琐“ 的描述信息。

关于 BDD 的本质,有另外一种表达方式:BDD 帮助开发人员设计软件,TDD 帮助开发人员测试软件。

Ginkgo 是 Go 语言中非常优秀的 BDD 框架,它通过 DSL 语法(Describe/Context/It)有效地帮助开发者组织与编排测试用例。本文只是展示了 Ginkgo 非常简单的用例,权当是抛砖引玉。

读者在使用 Ginkgo 过程中,需要理解它的执行生命周期, 重点包括  It、Context、Describe、BeforeEach、AfterEach、JustBeforeEach、BeforeSuite、AfterSuite、By、Fail  这些模块的执行顺序与语义逻辑。

最后,K8s 项目中也使用了 Ginkgo 框架,用于编写其端到端 (End to End,E2E) 测试用例,值得借鉴学习。

往期推荐

同步原语的基石

你真的懂string与[]byte的转换了吗

Go定时任务库:cron

CPU缓存体系对Go程序的影响

高挑的往事,给力!

机器铃砍菜刀

欢迎添加小菜刀微信

加入Golang分享群学习交流!

感谢你的点赞在看哦~