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是软件团队的一种工作方式。类似于软件开发的瀑布模型,都是用于开发软件的一种模式。
有以下几个特点:
瀑布开发模式
以前使用的开发模型大多都是瀑布开发模式,但是由于瀑布模型的先开发后测试的特性,导致代码交予测试后会有一大段时间代码开发人员处于空闲期,没活干,这大大的拖慢了软件开发的进度。
test-first programing
因为在开发中可能不会按照瀑布开发模型走,而是一边写代码一边测试,开发的同时不断的对代码进行完善。这样的做法叫test-first programing
。
测试驱动开发
如果在测试开发的过程中发现功能没办法使用现在可用的技术实现,也将大大的降低效率,任何代码不能开发到一半的时候才发现当前的设计方案行不通。所以在设计之前,技术上要做好测试,验证这样的设计在技术上是行得通的,然后在具体着手开发。这样的做法叫 test-driven development (TDD)
行为驱动开发
在开发过程中突然发现原本的功能几乎无用,或是别的功能或许更加重要,然后再这样的代码上做出针对性的调整。这样的做法叫:behavior-driven development (BDD)
行为驱动开发就是由测试驱动开发发展来的。它遵循持续迭代,小步快跑原则。
Step
是指Given
、When
、Then
、And
、But
这种,虽然程序在处理的时候,并不会对这些关键字做区分,但在写feature
文件的时候,我们需要做明确区分,方便我们合理的描述流程。
结合文章开头的例子,可能觉得例子太过于简单了。但实际上这个gherkin
语法支持的功能也是很丰富的。包括它的scenario outline
、background
等。
主要的关键字,点击查看详细信息:
Feature
Rule
(as of Gherkin 6)Example
(or Scenario
)Given
, When
, Then
, And
, But
for steps (or *
)Background
Scenario Outline
(or Scenario Template
)Examples
(or Scenarios
)几个常用的简单介绍
参考信息:
GitHub - cucumber/godog: Cucumber for golang
How to use godog | 渐行渐远 (neojos.com)