golang实现Cucumber BDD测试框架的插件库godog的使用

Golang实现Cucumber BDD测试框架的插件库godog的使用

godog是Golang官方支持的Cucumber BDD框架,它将规范和测试文档合并为一个整体,使用Given/When/Then格式的Gherkin场景描述。

为什么选择Godog/Cucumber

单一真实来源

Godog将规范和测试文档合并为一个整体。

活文档

因为规范会被Godog自动测试,所以它们总是保持最新。

关注客户

业务和IT并不总是相互理解。Godog的可执行规范鼓励更紧密的协作,帮助团队始终牢记业务目标。

减少返工

当自动化测试如此有趣时,团队可以轻松保护自己免受昂贵的回归影响。

完整示例Demo

步骤1 - 创建Go模块

mkdir godogs
cd godogs
go mod init godogs

步骤2 - 创建Gherkin特性文件

创建features/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

步骤3 - 创建godog步骤定义

创建godogs_test.go文件:

package main

import (
  "context"
  "errors"
  "fmt"
  "testing"

  "github.com/cucumber/godog"
)

// godogsCtxKey是用于在context.Context中存储可用godogs的键
type godogsCtxKey struct{}

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)
}

步骤4 - 创建主程序

创建godogs.go文件:

package main

// Godogs available to eat
var Godogs int

func main() { /* usual main func */ }

步骤5 - 运行测试

运行测试命令:

go test -v godogs_test.go

你应该看到类似以下的输出:

=== RUN   TestFeatures
Feature: eat godogs
  In order to be happy
  As a hungry gopher
  I need to be able to eat godogs
=== RUN   TestFeatures/Eat_5_out_of_12

  Scenario: Eat 5 out of 12          # features/godogs.feature:6
    Given there are 12 godogs        # godog_test.go:15 -> command-line-arguments.thereAreGodogs
    When I eat 5                     # godog_test.go:19 -> command-line-arguments.iEat
    Then there should be 7 remaining # godog_test.go:34 -> command-line-arguments.thereShouldBeRemaining

1 scenarios (1 passed)
3 steps (3 passed)
279.917µs
--- PASS: TestFeatures (0.00s)
    --- PASS: TestFeatures/Eat_5_out_of_12 (0.00s)
PASS
ok      command-line-arguments  0.164s

高级用法

使用TestMain运行测试套件

func TestMain(m *testing.M) {
  opts := godog.Options{
    Format:    "progress",
    Paths:     []string{"features"},
    Randomize: time.Now().UTC().UnixNano(), // 随机化场景执行顺序
  }

  status := godog.TestSuite{
    Name: "godogs",
    TestSuiteInitializer: InitializeTestSuite,
    ScenarioInitializer:  InitializeScenario,
    Options: &opts,
  }.Run()

  // 可选:除了godog外运行testing包的逻辑
  if st := m.Run(); st > status {
    status = st
  }

  os.Exit(status)
}

使用标签过滤场景

你可以使用-t=<expression>--tags=<expression>来过滤场景:

  • @wip - 运行所有带有wip标签的场景
  • ~@wip - 排除所有带有wip标签的场景
  • @wip && ~@new - 运行wip场景,但排除new场景
  • @wip,@undone - 运行wip或undone场景

使用断言库

func thereShouldBeRemaining(ctx context.Context, remaining int) error {
  assert.Equal(
    godog.T(ctx), Godogs, remaining, 
    "Expected %d godogs to be remaining, but there is %d", remaining, Godogs,
  )
  return nil
}

总结

Godog提供了一个强大的BDD测试框架,可以帮助团队更好地协作开发。通过Gherkin语法编写的测试用例既可作为文档,又可作为自动化测试,确保系统行为符合预期。


更多关于golang实现Cucumber BDD测试框架的插件库godog的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现Cucumber BDD测试框架的插件库godog的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Godog实现Golang中的BDD测试

Godog是Golang的一个BDD(行为驱动开发)测试框架,它是Cucumber的Golang实现版本。下面我将详细介绍如何使用Godog来编写BDD测试。

1. 安装Godog

首先需要安装Godog包:

go get github.com/cucumber/godog/cmd/godog@latest

2. 基本使用

2.1 创建feature文件

features目录下创建.feature文件,例如calculator.feature:

Feature: Calculator
  In order to avoid silly mistakes
  As a math idiot
  I want to be told the sum of two numbers

  Scenario: Add two numbers
    Given I have entered 50 into the calculator
    And I have entered 70 into the calculator
    When I press add
    Then the result should be 120 on the screen

2.2 实现步骤定义

创建测试文件calculator_test.go:

package main

import (
	"github.com/cucumber/godog"
)

type calculator struct {
	result int
}

func (c *calculator) iHaveEnteredIntoTheCalculator(arg1 int) error {
	c.result = arg1
	return nil
}

func (c *calculator) iPressAdd() error {
	// 这里实现加法逻辑
	// 示例中简化处理
	c.result += c.result
	return nil
}

func (c *calculator) theResultShouldBeOnTheScreen(arg1 int) error {
	if c.result != arg1 {
		return fmt.Errorf("expected %d, but got %d", arg1, c.result)
	}
	return nil
}

func InitializeScenario(ctx *godog.ScenarioContext) {
	calc := &calculator{}
	
	ctx.Step(`^I have entered (\d+) into the calculator$`, calc.iHaveEnteredIntoTheCalculator)
	ctx.Step(`^I press add$`, calc.iPressAdd)
	ctx.Step(`^the result should be (\d+) on the screen$`, calc.theResultShouldBeOnTheScreen)
}

2.3 创建测试入口

创建godog_test.go文件:

package main

import (
	"testing"
	"github.com/cucumber/godog"
)

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")
	}
}

3. 高级功能

3.1 使用表格数据

可以在feature文件中使用表格:

Scenario Outline: Add two numbers
  Given I have entered <a> into the calculator
  And I have entered <b> into the calculator
  When I press add
  Then the result should be <result> on the screen

  Examples:
    | a  | b  | result |
    | 1  | 2  | 3      |
    | 5  | 5  | 10     |
    | 10 | 20 | 30     |

3.2 钩子函数

Godog支持多种钩子函数:

func InitializeScenario(ctx *godog.ScenarioContext) {
	// 在场景开始前执行
	ctx.BeforeScenario(func(sc *godog.Scenario) {
		fmt.Println("Before scenario:", sc.Name)
	})

	// 在场景结束后执行
	ctx.AfterScenario(func(sc *godog.Scenario, err error) {
		fmt.Println("After scenario:", sc.Name, "with error:", err)
	})

	// 在步骤前执行
	ctx.BeforeStep(func(st *godog.Step) {
		fmt.Println("Before step:", st.Text)
	})

	// 在步骤后执行
	ctx.AfterStep(func(st *godog.Step, err error) {
		fmt.Println("After step:", st.Text, "with error:", err)
	})
}

3.3 自定义输出格式

Godog支持多种输出格式:

suite := godog.TestSuite{
	Options: &godog.Options{
		Format: "junit", // 可以是pretty, progress, junit等
		Output: colors.Colored(os.Stdout),
		Paths:  []string{"features"},
	},
}

4. 运行测试

运行测试有两种方式:

  1. 使用go test:
go test -v
  1. 直接使用godog命令:
godog

5. 实际项目结构示例

project/
├── features/
│   ├── calculator.feature
│   └── other.feature
├── go.mod
├── go.sum
├── godog_test.go
└── internal/
    └── calculator/
        ├── calculator.go
        └── calculator_test.go

Godog是一个强大的BDD测试框架,可以帮助团队更好地协作,通过自然语言描述测试场景,同时保持测试代码的可维护性。它特别适合需要业务人员参与测试用例设计的项目。

回到顶部