介绍
godog和go test做的是一样的事,都是测试代码的。只是换了一种形式。
godog是Golang的官方Cucumber BDD框架,它将规范和测试文档合并为一个有凝聚力的整体,使用Gherkin格式的场景,格式为Given,When,Then。
使用
目的:我们要测试一个吃东西的功能是否已经实现。
使用go get 安装
go get github.com/cucumber/godog/cmd/godog@v0.12.0
或是是安装二进制文件使用go install
go install github.com/cucumber/godog/cmd/godog@latest
创建一个feature文件夹,并在该文件夹中创建godogs.feature
文件,内容如下
Feature: eat godogs In order to be happy As a hungry gopher I need to be able to eat godogs Scenario: Eat 5 out of 12 Given there are 12 godogs When I eat 5 Then there should be 7 remaining
然后在控制台使用godog run
会出现如下内容
Feature: eat godogs In order to be happy As a hungry gopher I need to be able to eat godogs Scenario: Eat 5 out of 12 # features/godogs.feature:6 Given there are 12 godogs When I eat 5 Then there should be 7 remaining 1 scenarios (1 undefined) 3 steps (3 undefined) 220.129µs You can implement step definitions for undefined steps with these snippets: func iEat(arg1 int) error { return godog.ErrPending } func thereAreGodogs(arg1 int) error { return godog.ErrPending } func thereShouldBeRemaining(arg1 int) error { return godog.ErrPending } func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^I eat (\d+)$`, iEat) ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs) ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) }
新建一个godogs_test.go
文件。
将上面的函数复制到godogs_test.go
中。
package main import "github.com/cucumber/godog" func iEat(arg1 int) error { return godog.ErrPending } func thereAreGodogs(arg1 int) error { return godog.ErrPending } func thereShouldBeRemaining(arg1 int) error { return godog.ErrPending } func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^I eat (\d+)$`, iEat) ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs) ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) }
再次运行godog run
。
这次我们可以看到
Feature: eat godogs In order to be happy As a hungry gopher I need to be able to eat godogs Scenario: Eat 5 out of 12 # features/godogs.feature:6 Given there are 12 godogs # godogs_test.go:10 -> thereAreGodogs TODO: write pending definition When I eat 5 # godogs_test.go:6 -> iEat Then there should be 7 remaining # godogs_test.go:14 -> thereShouldBeRemaining 1 scenarios (1 pending) 3 steps (1 pending, 2 skipped) 282.123µs
但函数有错误返回时将不会通过,所以我们应该修改函数的返回,或者是函数没有错误,不给返回值。如
func iEat(arg1 int) { // Eat arg1. }
下面完善行为流程。将下面的代码复制到godogs_test.go
文件中。
package godogs import ( "context" "errors" "fmt" "testing" "github.com/cucumber/godog" ) // godogsCtxKey 是用来在context.Context中存储可用godogs的键。 type godogsCtxKey struct{} // 错误在三个步骤定义中返回 nil,方案将成功通过。 func thereAreGodogs(ctx context.Context, available int) (context.Context, error) { return context.WithValue(ctx, godogsCtxKey{}, available), nil } func iEat(ctx context.Context, num int) (context.Context, error) { // 使用断言 available, ok := ctx.Value(godogsCtxKey{}).(int) if !ok { return ctx, errors.New("there are no godogs available") } if available < num { return ctx, fmt.Errorf("you cannot eat %d godogs, there are %d available", num, available) } available -= num return context.WithValue(ctx, godogsCtxKey{}, available), nil } func thereShouldBeRemaining(ctx context.Context, remaining int) error { available, ok := ctx.Value(godogsCtxKey{}).(int) if !ok { return errors.New("there are no godogs available") } if available != remaining { return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, available) } return nil } func TestFeatures(t *testing.T) { // 配置测试套件 suite := godog.TestSuite{ ScenarioInitializer: InitializeScenario, Options: &godog.Options{ // 格式名称 Format: "pretty", // 所有特征文件路径 Paths: []string{"features"}, // 运行子测试的测试实列 TestingT: t, }, } if suite.Run() != 0 { t.Fatal("non-zero status returned, failed to run feature tests") } } func InitializeScenario(sc *godog.ScenarioContext) { sc.Step(`^there are (\d+) godogs$`, thereAreGodogs) sc.Step(`^I eat (\d+)$`, iEat) sc.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining) }
再次执行godog run
命令,发现全部通过,则功能已经实现,若是最后出现没有通过的情况,则是逻辑出错,请仔细检查更正后继续测试。
BDD 行为驱动开发
什么是BDD?
BDD是软件团队的一种工作方式。类似于软件开发的瀑布模型,都是用于开发软件的一种模式。
有以下几个特点:
- 鼓励跨角色协作,以建立对要解决的问题的共同理解
- 在快速、小的迭代中工作,以增加反馈和价值流动
- 生成系统文档,根据系统行为自动检查
发展史
瀑布开发模式
以前使用的开发模型大多都是瀑布开发模式,但是由于瀑布模型的先开发后测试的特性,导致代码交予测试后会有一大段时间代码开发人员处于空闲期,没活干,这大大的拖慢了软件开发的进度。
test-first programing
因为在开发中可能不会按照瀑布开发模型走,而是一边写代码一边测试,开发的同时不断的对代码进行完善。这样的做法叫test-first programing
。
测试驱动开发
如果在测试开发的过程中发现功能没办法使用现在可用的技术实现,也将大大的降低效率,任何代码不能开发到一半的时候才发现当前的设计方案行不通。所以在设计之前,技术上要做好测试,验证这样的设计在技术上是行得通的,然后在具体着手开发。这样的做法叫 test-driven development (TDD)
行为驱动开发
在开发过程中突然发现原本的功能几乎无用,或是别的功能或许更加重要,然后再这样的代码上做出针对性的调整。这样的做法叫:behavior-driven development (BDD)
行为驱动开发就是由测试驱动开发发展来的。它遵循持续迭代,小步快跑原则。
Step
Step
是指Given
、When
、Then
、And
、But
这种,虽然程序在处理的时候,并不会对这些关键字做区分,但在写feature
文件的时候,我们需要做明确区分,方便我们合理的描述流程。
结合文章开头的例子,可能觉得例子太过于简单了。但实际上这个gherkin
语法支持的功能也是很丰富的。包括它的scenario outline
、background
等。
主要的关键字,点击查看详细信息:
Feature
Rule
(as of Gherkin 6)Example
(orScenario
)Given
,When
,Then
,And
,But
for steps (or*
)Background
Scenario Outline
(orScenario Template
)Examples
(orScenarios
)
几个常用的简单介绍
- Feature:描述我们需要测试的功能
- Scenario: 描述测试场景
- Given: 描述初始上下文
- When: 描述一个事件(强烈建议每个方案只有一个步骤)
- Then: 描述预期结果(应基于可观察的输出)
参考信息:
GitHub - cucumber/godog: Cucumber for golang
How to use godog | 渐行渐远 (neojos.com)