ginkgo:初学者指南

ginkgo:初学者指南什么是 ginkgo ginkgo 是一个用 go 写的 BDD Behavior Driven Development 的测试框架 一般用于 Go 服务的集成测试 ginkgo 的特点 BDD 的代码风格 Describe delete app api func It should delete app

大家好,我是讯享网,很高兴认识大家。

什么是ginkgo:
ginkgo是一个用go写的BDD(Behavior Driven Development)的测试框架,一般用于Go服务的集成测试。

ginkgo的特点
BDD的代码风格

Describe("delete app api",func(){ 
    It("should delete app permanently",func(){ 
   ...}) It("should delete app failed if services existed", func(){ 
   ...})

讯享网

这段ginkgo的心得体会摘自七牛云测试团队,大卡尔的使用体会

讯享网Ginkgo定义的DSL语法(Describe/Context/It)可以非常方便的帮助大家组织和编排测试用例。 在BDD模式中,测试用例的标题书写,要非常注意表达,要能清晰的指明用例测试的业务场景。 只有这样才能极大的增强用例的可读性,降低使用和维护的心智负担。 可读性这一点,在自动化测试用例设计原则上,非常重要。因为测试用例不同于一般意义上的程序, 它在绝大部分场景下,看起来都像是一段段独立的方法,每个方法背后隐藏的业务逻辑也是细小的,不具通识性。 这个问题在用例量少的情况下,还不明显。但当用例数量上到一定量级,你会发现,如果能快速理解用例到底是能做什么的,真的非常重要。 而这正是BDD能补足的地方。 不过还是要强调,Ginkgo只是提供对BDD模式的支持,你的用例最终呈现的效果,还是依赖你自己的书写。 

ginkgo安装

$ go get github.com/onsi/ginkgo/ginkgo $ go get github.com/onsi/gomega/... 

ginkgo常用模块

讯享网常用的10个:It、Context、Describe、BeforeEach、AfterEach、JustBeforeEach、BeforeSuite、AfterSuite、By、Fail 

It模块

It是测试例的基本单位,即It包含的代码就算一个测试用例 It可以理解维测试代码的最小单元 

Context和Describe 模块

讯享网Context和Describe的功能都是将一个或多个测试例归类 一个describe可以包含多个context,一个context可以包含多个IT模块 

BeforeEach模块

BeforeEach是每个测试例执行前执行该段代码 比如创建数据库连接就可以使用BeforeEach ,每个BeforeEach只在当前域内起作用。 执行顺序是同一层级的顺序执行,不同层级的从外层到里层以此执行。类似与 全局变量和局部变量的区别 

AfterEach模块

讯享网AfterEach是每个测试例执行后执行该段代码 比如销毁数据库连接,一般用于测试例执行完成后进行数据清理,也可以用于结果判断 

JustBeforeEach,

JustBeforeEach是在BeforeEach执行之后,测试例执行之前执行 测试用例执行前的一些前置操作 

BeforeSuite模块

讯享网BeforeSuite是在该测试集执行前执行,即该文件夹内的测试例执行之前 BeforeSuite和AfterSuite写在_suite_test.go文件中,会在所有测试例执行之前和之后执行 如果BeforeSuite执行失败,则这个测试集都不会被执行 

Tip:使用C中断执行时,AfterSuite仍然会被执行,需要再使用一次C中断

AfterSuite模块

AfterSuite是在该测试集执行后执行,即该文件夹内的测试例执行完后 

By模块

讯享网By是打印信息,内容只能是字符串,只会在测试例失败后打印,一般用于调试和定位问题 

Fail模块

Fail是标志该测试例运行结果为失败,并打印里面的信息 

Specify模块

讯享网Specify和It功能完全一样,It属于其简写 

ginkgo的三个标志
F、X和P,可以用在Describe、Context、It等任何包含测试例的模块


讯享网

P的含义是Pending,即不执行,用法和F一样,规则的外层的生效

It("should do something, if it can", func() { 
    if !someCondition { 
    Skip("special condition wasn't met") } // assertions go here }) 

ginkgo 并发设置

讯享网ginkgo -p 使用默认并发数 ginkgo -nodes=N 自己设定并发数 

默认并发数是用的参数runtime.NumCPU()值,即逻辑CPU个数,大于4时,用runtime.NumCPU()-1

如果需要显示实时日志,需要添加 -stream参数

并发执行时打印的日志是汇总后经过合并处理再打印的,所以看起来比较规范, 每个测试例的内容也都打印在一起,但时不实时,如果需要实时打印,加-stream参数,缺点是每个测试例日志交叉打印 

ginkgo goroutine设置
在平时的代码中,我们经常会看到需要做异步处理的测试用例。但是这块的逻辑如果处理不好,用例可能会因为死锁或者未设置超时时间而异常卡住,非常的恼人。好在Ginkgo专门提供了原生的异步支持,能大大降低此类问题的风险。类似用法:

讯享网 It("should post to the channel, eventually", func(done Done) { 
    c := make(chan string, 0) go DoSomething(c) Expect(<-c).To(ContainSubstring("Done!")) close(done) }, 0.2) 

0.2的单位是秒

ginkgo性能测试
使用这个模块Measure

Measure("it should do something hard efficiently", func(b Benchmarker) { 
    runtime := b.Time("runtime", func() { 
    output := SomethingHard() Expect(output).To(Equal(17)) }) Ω(runtime.Seconds()).Should(BeNumerically("<", 0.2), "SomethingHard() shouldn't take too long.") b.RecordValue("disk usage (in MB)", HowMuchDiskSpaceDidYouUse()) }, 10) 

ginkgo命令行使用

讯享网ginkgo bootstrap <FLAGS> 创建测试关联文件 ginkgo generate <filename(s)> 生成测试代码模版 ginkgo nodot 更新测试套件中的nodot声明 ginkgo convert /path/to/package 转变包文件格式为ginkgo可识别的格式 ginkgo unfocus (or ginkgo blur) 递归地取消当前目录下所有集中测试的焦点 ginkgo version 输出版本信息 

ginkgo初级实战
1.本地gopath/src下创建一个项目books
2. 创建 books.go 文件

package books import ( "encoding/json" "fmt" ) type Book struct { 
    Title string Author string Pages int } func (b Book) AuthorLastName() (interface{ 
   }, interface{ 
   }) { 
    fmt.Println("AuthorLastName") return b.Author,b.Title } func (b Book) CategoryByLength() string{ 
    if b.Pages >300{ 
    return "NOVEL" } else if b.Pages<100 { 
    return "SMALL STORY" } else { 
    return "SHORT STORY" } } func NewBookFromJSON(json json.Decoder) error { 
    book:=json.Decode(json) return book } 
  1. 如果go版本高于1.11 引入go moudle的原因 , 创建go.mod包管理文件 go mod init
    当前文件夹下会生成两个文件 go.mod go.sum
讯享网->cat go.mod module books go 1.14 require ( github.com/onsi/ginkgo v1.12.0 github.com/onsi/gomega v1.9.0 golang.org/x/sync v0.0.0-054-43a5402ce75a // indirect ) ->cat go.sum github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= golang.org/x/net v0.0.0-101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-948-bdbb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA= golang.org/x/sys v0.0.0-948-bdbb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/xerrors v0.0.0-122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-325-20d25e h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-325-20d25e/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-613-ddf1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-613-ddf1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -> 
  1. 创建测试关联文件
    进入项目当前路径下执行 ginkgo bootstrap 项目下会创建一个 books_suite_test.go文件,为测试用例入口
package books_test import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "testing" ) func TestBooks(t *testing.T) { 
    RegisterFailHandler(Fail) RunSpecs(t, "Books Suite") } 
  1. 创建测试模版文件 ginkgo generate books 当前的包名字叫 books所以 创建出来的测试模版文件叫
    books_test.go
讯享网package books_test import ( . "/path/to/books" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Book", func() { 
    }) 
package books_test import ( . "books" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Book", func() { 
    var ( longBook Book shortBook Book smallBook Book ) BeforeEach(func() { 
    longBook = Book{ 
    Title: "Les Miserables", Author: "Victor Hugo", Pages: 1488, } shortBook = Book{ 
    Title: "Fox In Socks", Author: "Dr. Seuss", Pages: 240, } smallBook = Book{ 
    Title: "go program", Author: "caochunhui", Pages: 20, } }) Describe("Categorizing book length", func() { 
    Context("With more than 300 pages", func() { 
    It("should be a novel", func() { 
    Expect(longBook.CategoryByLength()).To(Equal("NOVEL")) }) }) Context("With fewer than 300 pages", func() { 
    It("should be a short story", func() { 
    Expect(shortBook.CategoryByLength()).To(Equal("SHORT STORY")) }) }) Context("With fewer than 100 pages", func() { 
    It("should be a small story", func() { 
    Expect(smallBook.CategoryByLength()).To(Equal("SMALL STORY")) }) }) }) }) 

当前这个测试代码中我们写了三个用例,分别测试books源代码中CategoryByLength功能所对应的三个逻辑,即根据书页的多少判断书本的类型,测试代码只需要覆盖所有的逻辑即可。
6. 执行测试代码
这块有三种执行办法
go test -v
ginkgo
还可以 ginko build 编译成二进制,执行二进制
在这里插入图片描述
可以看到输出了测试结果
7.输出JUnit测试报告
ginkgo支持输出junit的测试报告 ,这块需要修改一下套件文件books_suite_test.go 将原始的
RunSpecs(t, “Books Suite”) 直接运行,修改为生成report报告运行方式

讯享网func TestBooks(t *testing.T) { 
    RegisterFailHandler(Fail) //RunSpecs(t, "Books Suite") junitReporter := reporters.NewJUnitReporter("junit.xml") RunSpecsWithDefaultAndCustomReporters(t, "Books Suite", []Reporter{ 
   junitReporter}) } 
<?xml version="1.0" encoding="UTF-8"?> <testsuite name="Books Suite" tests="3" failures="0" errors="0" time="0"> <testcase name="Book Categorizing book length With more than 300 pages should be a novel" classname="Books Suite" time="5.0482e-05"></testcase> <testcase name="Book Categorizing book length With fewer than 300 pages should be a short story" classname="Books Suite" time="1.111e-06"></testcase> <testcase name="Book Categorizing book length With fewer than 100 pages should be a small story" classname="Books Suite" time="7.7e-07"></testcase> </testsuite> 

一个简单的ginkgo测试框架体验到此结束,后续更新高级玩法。

参考文档
http://onsi.github.io/ginkgo/
https://s0godoc0org.icopy.site/github.com/onsi/ginkgo
https://blog.csdn.net/goodboynihaohao/article/details/

小讯
上一篇 2025-02-13 11:40
下一篇 2025-01-29 20:37

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/18218.html