searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Golang BDD框架Godog系列(1)

2023-06-21 01:35:02
266
0

简介

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
│&nbsp;&nbsp; └── godogs.feature
├── go.mod
├── go.sum
└── godogs_test.go

1 directory, 5 files

 

使用小结

  1. 参考Gherkin语法定义声明描述文件
  2. godog run生成代码骨架
  3. 补充代码骨架测试用例,添加Test开头入口函数,执行go test即可
0条评论
0 / 1000
c****m
2文章数
1粉丝数
c****m
2 文章 | 1 粉丝
c****m
2文章数
1粉丝数
c****m
2 文章 | 1 粉丝
原创

Golang BDD框架Godog系列(1)

2023-06-21 01:35:02
266
0

简介

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
│&nbsp;&nbsp; └── godogs.feature
├── go.mod
├── go.sum
└── godogs_test.go

1 directory, 5 files

 

使用小结

  1. 参考Gherkin语法定义声明描述文件
  2. godog run生成代码骨架
  3. 补充代码骨架测试用例,添加Test开头入口函数,执行go test即可
文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
1
1