简介
Godog是一款开源的,golang语言生态中的,一个BDD(行为驱动开发)的测试框架。Godog基于Cucumber生态,使用Gherkin语法描述测试用例,可以很方便的跨团队进行合作以构建充分的测试场景,保障产品按照预期的质量交付。
使用Godog进行开发测试具有以下好处(以下摘自项目说明):
1. 一致性 -- Godog将声明和测试的文档内聚为一个整体,保证声明和测试一致
2. 实时有效的声明文档 -- 因为Godog将声明自动执行,所以声明文档可以一致保持最新
3. 专注于服务客户 -- 通过使用领域语言,促进跨团队的合作,更容易对齐目标,完成对客户的交付
4. 减少重复工作 -- 通过到自动化测试的遍历,团队可以很容易地保护自己免受代价高昂的回归。
什么是BDD
行为驱动开发 (BDD) 是一个开发过程,与测试驱动开发(TDD)不同的是:它优先考虑的是技术团队和非技术团队之间的协作。BDD通常以以用户故事为视角进行思考如何开发和测试。
什么是Cucumber
Cucumber一个流行的 BDD 协作开源平台,通过解析Gherkin语法定义的场景,步骤,来验证系统的实现是否和定义描述的一致。Cucumber提供了对主流语言的支持,提供了丰富的工具链可以实现跨语言迁移场景。
Gherkin
Gherkin是一种DSL(领域特定语言),通过使用Gherkin,我们可以直观的定义系统的功能描述。基本的描述框架为
- Given-用例开始执行的一些初始化操作。
- When-用例执行的步骤,例如发送请求,点击元素等。
- Then-用例执行完预期的结果,用于验证是否符合预期。
通过上面的关键词进行编排步骤,并提供诸如Examples,Backendgroud,DataTable,Tag等支持,可以非常方便的完善我们的测试用例描述,降低我们编写测试的的成本。
基本使用
安装
通过下面的命令即可安装godog
go install github.com/cucumber/godog/cmd/godog@latest
获取命令的使用帮助
➜ ~ godog -h
Creates and runs test runner for the given feature files.
Command should be run from the directory of tested package
and contain buildable go source.
Usage:
godog [flags]
godog [command]
Available Commands:
build Compiles a test runner
completion Generate the autocompletion script for the specified shell
help Help about any command
run Compiles and runs a test runner
version Show current version
Flags:
-h, --help help for godog
Use "godog [command] --help" for more information about a command.
使用示例(参考官方文档)
创建文件夹, 并初始化项目
mkdir godogs // 示例描述目录
cd godogs
go mod init godogs // 初始化go项目
mkdir features // 描述文件目录
创建一个声明描述文件
echo "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" > features/godogs.feature
执行Godog命令,获取到自动生成的代码
➜ godogs godog run ./features
Use of godog CLI is deprecated, please use *testing.T instead.
See https://github.com/cucumber/godog/discussions/478 for details.
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)
441.898µ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文件中, 调整下顺序
package godogs
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(`^there are (\d+) godogs$`, thereAreGodogs)
ctx.Step(`^I eat (\d+)$`, iEat)
ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}
运行测试, 此时因为我们没有实现测试方法,都返回了pending error。所以结果是没有测试通过
➜ godogs godog run ./features
Use of godog CLI is deprecated, please use *testing.T instead.
See https://github.com/cucumber/godog/discussions/478 for details.
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)
884.32µs
修改代码如下,补齐测试功能
package godogs
import (
"errors"
"fmt"
"github.com/cucumber/godog"
)
var (
godogsNum int
)
func iEat(arg1 int) error {
if godogsNum < arg1 {
return errors.New("godogs not enough")
}
godogsNum -= arg1
return nil
}
func thereAreGodogs(arg1 int) error {
godogsNum = arg1
return nil
}
func thereShouldBeRemaining(arg1 int) error {
if arg1 == godogsNum {
return nil
}
return fmt.Errorf("godogs remain num not match, expect:%d, actual:%d", arg1, godogsNum)
}
func InitializeScenario(ctx *godog.ScenarioContext) {
ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs)
ctx.Step(`^I eat (\d+)$`, iEat)
ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}
再次运行测试,可以看到测试通过
➜ godogs godog run ./features
Use of godog CLI is deprecated, please use *testing.T instead.
See https://github.com/cucumber/godog/discussions/478 for details.
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:22 -> thereAreGodogs
When I eat 5 # godogs_test.go:13 -> iEat
Then there should be 7 remaining # godogs_test.go:26 -> thereShouldBeRemaining
1 scenarios (1 passed)
3 steps (3 passed)
1.221143ms
这时还是只能godog run来执行,但是godog run已经过时了,标准Go测试应执行go test
,尝试运行,显示没有测试代码需要执行
➜ godogs go test
testing: warning: no tests to run
PASS
ok godogs 0.016s
godogs_test.go补充测试执行入口方法,文件内容变更如下
package godogs
import (
"errors"
"fmt"
"github.com/cucumber/godog"
)
var (
godogsNum int
)
func iEat(num int) error {
if godogsNum < num {
return errors.New("godogs not enough")
}
godogsNum -= num
return nil
}
func thereAreGodogs(num int) error {
godogsNum = num
return nil
}
func thereShouldBeRemaining(remainNum int) error {
if remainNum == godogsNum {
return nil
}
return fmt.Errorf("godogs remain num not match, expect:%d, actual:%d", remainNum, godogsNum)
}
func TestFeatures(t *testing.T) {
suite := godog.TestSuite{
ScenarioInitializer: InitializeScenario,
Options: &godog.Options{
Format: "pretty",
Paths: []string{"features"},
TestingT: t, // Testing instance that will run subtests.
},
}
if suite.Run() != 0 {
t.Fatal("non-zero status returned, failed to run feature tests")
}
}
func InitializeScenario(ctx *godog.ScenarioContext) {
ctx.Step(`^there are (\d+) godogs$`, thereAreGodogs)
ctx.Step(`^I eat (\d+)$`, iEat)
ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}
执行 go test,符合预期
➜ godogs go test
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:23 -> godogs.thereAreGodogs
When I eat 5 # godogs_test.go:14 -> godogs.iEat
Then there should be 7 remaining # godogs_test.go:27 -> godogs.thereShouldBeRemaining
1 scenarios (1 passed)
3 steps (3 passed)
428.994µs
PASS
ok godogs 0.019s
最终项目目录如下
➜ godogs tree -L 3 ../godogs
../godogs
├── features
│ └── godogs.feature
├── go.mod
├── go.sum
└── godogs_test.go
1 directory, 5 files
使用小结
- 参考Gherkin语法定义声明描述文件
- godog run生成代码骨架
- 补充代码骨架测试用例,添加Test开头入口函数,执行go test即可