Ginkgo是一个基于Go语言的BDD测试框架,一般用于Go服务的集成测试。
本文的内容部分来自Ginkgo网站,部分来自使用过程中的经验总结。
Ginkgo网址:http://onsi.github.io/ginkgo/
源码链接:https://github.com/onsi/ginkgo
1.安装Ginkgo
go get github.com/onsi/ginkgo/ginkgo
go get github.com/onsi/gomega/… 附加的库,配合使用,下一篇会详细讲解
配置环境变量,加到$GOPATH/bin或$PATH
2.新建
example_test.go代码中默认会import当前文件夹
3.模块
常用的10个:It、Context、Describe、BeforeEach、AfterEach、JustBeforeEach、BeforeSuite、AfterSuite、By、Fail
还有一个Specify和It功能完全一样,It属于其简写
4.使用
var _ = Describe("Book", func() {
var (
book Book
err error
json string
)
BeforeEach(func() {
json = `{
"title":"Les Miserables",
"author":"Victor Hugo",
"pages":1488
}`
})
JustBeforeEach(func() {
book, err = NewBookFromJSON(json)
})
AfterEach(func() {
By("End One Test")
})
Describe("loading from JSON", func() {
Context("when the JSON parses succesfully", func() {
It("should populate the fields correctly", func() {
Expect(book.Title).To(Equal("Les Miserables"))
Expect(book.Author).To(Equal("Victor Hugo"))
Expect(book.Pages).To(Equal(1488))
})
It("should not error", func() {
Expect(err).NotTo(HaveOccurred())
})
})
Context("when the JSON fails to parse", func() {
BeforeEach(func() {
json = `{
"title":"Les Miserables",
"author":"Victor Hugo",
"pages":1488oops
}`
})
It("should return the zero-value for the book", func() {
Expect(book).To(BeZero())
})
It("should error", func() {
if err != nil {
Fail("This Case Failed")
}
})
})
})
Describe("Extracting the author's last name", func() {
It("should correctly identify and return the last name", func() {
Expect(book.AuthorLastName()).To(Equal("Hugo"))
})
})
})
func TestBooks(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Books Suite")
}
var _ = BeforeSuite(func() {
dbRunner = db.NewRunner()
err := dbRunner.Start()
Expect(err).NotTo(HaveOccurred())
dbClient = db.NewClient()
err = dbClient.Connect(dbRunner.Address())
Expect(err).NotTo(HaveOccurred())
})
var _ = AfterSuite(func() {
dbClient.Cleanup()
dbRunner.Stop()
})
Tip:使用^C中断执行时,AfterSuite仍然会被执行,需要再使用一次^C中断
5.标志
有三个:F、X和P,可以用在Describe、Context、It等任何包含测试例的模块
FDescribe("outer describe", func() {
It("A", func() { ... })
It("B", func() { ... })
})
Tip:当里层和外层都存在Focus时,外层的无效,即下面代码只会执行B测试用例
FDescribe("outer describe", func() {
It("A", func() { ... })
FIt("B", func() { ... })
})
还有一个跳过测试例的方式是在代码中加Skip
It("should do something, if it can", func() {
if !someCondition {
Skip("special condition wasn't met")
}
// assertions go here
})
条件满足时,会跳过该测试用例
6.并发
ginkgo -p 使用默认并发数
ginkgo -nodes=N 自己设定并发数
默认并发数是用的参数runtime.NumCPU()值,即逻辑CPU个数,大于4时,用runtime.NumCPU()-1
并发执行时打印的日志是汇总后经过合并处理再打印的,所以看起来比较规范,每个测试例的内容也都打印在一起,但时不实时,如果需要实时打印,加-stream参数,缺点是每个测试例日志交叉打印
7.goroutine
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)
Ginkgo检测到Done类型参数,就会自动设置超时时间,就是后面那个0.2,单位是秒
8.DesctibeTable用法
有时候很多测试例除了数据部分其他都是相同的,写很多类似的It会很繁琐,于是有Table格式出现
package table_test
import (
. "github.com/onsi/ginkgo/extensions/table"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Math", func() {
DescribeTable("the > inequality",
func(x int, y int, expected bool) {
Expect(x > y).To(Equal(expected))
},
Entry("x > y", 1, 0, true),
Entry("x == y", 0, 0, false),
Entry("x < y", 0, 1, false),
)
})
等同于
package table_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Math", func() {
Describe("the > inequality",
It("x > y", func() {
Expect(1 > 0).To(Equal(true))
})
It("x == y", func() {
Expect(0 > 0).To(Equal(false))
})
It("x < y", func() {
Expect(0 > 1).To(Equal(false))
})
)
})
一般生成Junit的XML测试报告
func TestFoo(t *testing.T) {
RegisterFailHandler(Fail)
junitReporter := reporters.NewJUnitReporter("junit.xml")
RunSpecsWithDefaultAndCustomReporters(t, "Foo Suite", []Reporter{junitReporter})
}
使用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)
该测试例会运行10次,并打印出执行性能数据
• [MEASUREMENT]
Suite
it should do something hard efficiently
Ran 10 samples:
runtime:
Fastest Time: 0.01s
Slowest Time: 0.08s
Average Time: 0.05s ± 0.02s
disk usage (in MB):
Smallest: 3.0
Largest: 5.2
Average: 3.9 ± 0.4