Ginkgo测试框架入门
为什么选择Ginkgo
目前基于go语言较为流行的测试框架:
testify(TDD)
goconvey(BDD)
Ginkgo(BDD)
在需求沟通上,若开发对需求的理解有偏差,就容易发生摩托变单车的事情。而BDD行为驱动测试就是为了解决这个问题,即先写功能描述。开发,测试,产品等都可以看懂,能低成本地纠正错误。
BDD可以得到我们对产品的理解提供反馈,更符合互联网团队目前对功能点的验收测试,也可结合TDD框架testify做更为细致的测试。
使用过rspec框架的会对Ginkgo的语法比较亲切,可以减少学习成本,Ginkgo的函数表达能力比较强, 功能也比较齐全
Name
Ginkgo
GoConvey
testify
Assertions
Gomega
Style
spec
spec
assert
Equal
✓
✓
✓
IsSame
✓
✓
DeepEqual
✓
✓
True
✓
✓
✓
False
✓
✓
✓
Nil
✓
✓
✓
Empty
✓
✓
✓
Error
✓
✓
Implements
✓
IsType
✓
✓
✓
StringContains
✓
✓
✓
StringMatches
✓
Collection
✓
✓
Panics
✓
✓
✓
HasLen
✓
Matches
✓
Satisfy
Within
框架简介
Ginkgo是golang的BDD类型的测试框架, ginkgo官方推进的匹配库是gomega, 可以用它代替go内置的Testing的语法库,可以减少代码书写量,且语意更明确。
Quick Start
Step1. 安装
$ go get github.com/onsi/ginkgo/ginkgo
$ go get github.com/onsi/gomega/...
Step2. 生成测试套件Suite
$ cd path/to/books
$ ginkgo bootstrap
上述命令会自动生成,如下代码:
//path/to/books/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")
}
需要注意的是这里package为 books_test, go中package的名字需要跟文件所在目录名一致packageName, 而packageName_test则是特例,在go中是允许的
Step3. 生成specs
$ ginkgo generate book
上述命令会自动生成,如下代码:
//path/to/books/book_test.go
package books_test
import (
. "/path/to/books"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Book", func() {
})
Step4. 添加specs
//path/to/books/books_suite_test.go
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)
})
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() {
Expect(err).To(HaveOccurred())
})
})
})
Describe("Extracting the author's last name", func() {
It("should correctly identify and return the last name", func() {
Expect(book.AuthorLastName()).To(Equal("Hugo"))
})
})
})
method
Ginkgo提供了一系列拥可以嵌套的函数,来更丰富地描述测试,下面举几个比较常用的函数
Describe
描述一种行为或者一个方法
Context
丰富Describe所描述的行为或方法,增加条件语句,尽可能全地覆盖各种condition
it
申明用例, 期望这个用例得到的结果
Expect
这个是gomega提供的方法,用来断言结果
BeforeEach
会在每个小于等于beforeEach嵌套层的it函数之前运行,来设置公用的数据变量
JustBeforeEach
会在所有BeforeEach执行之后运行,在每个小于等于JustBeforeEach嵌套层的it函数之前运行, 可以有效避免重复创建
Mock
Ginkgo没有提供相关的mock方法,Ginkgo作者认为可以通过依赖注入和通过interface来实现, 他认为这比mock和stubs更清楚和富有表现力,话虽如此,但Gomock这个package,Ginkgo作者是比较推荐的,他实现mock相对来说比较简单
import (
"code.google.com/p/gomock/gomock"
. github.com/onsi/ginkgo
. github.com/onsi/gomega
)
var _ = Describe("Consumer", func() {
var (
mockCtrl *gomock.Controller
mockThing *mockthing.MockThing
consumer *Consumer
)
BeforeEach(func() {
mockCtrl = gomock.NewController(GinkgoT())
mockThing = mockthing.NewMockThing(mockCtrl)
consumer = NewConsumer(mockThing)
})
AfterEach(func() {
mockCtrl.Finish()
})
It("should consume things", func() {
mockThing.EXPECT().OmNom()
consumer.Consume()
})
})
补充
此文档仅供快速入门,更多详细用法可以查询官方文档