Go ---- godog的使用

介绍

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是软件团队的一种工作方式。类似于软件开发的瀑布模型,都是用于开发软件的一种模式。

有以下几个特点:

  • 鼓励跨角色协作,以建立对要解决的问题的共同理解
  • 在快速、小的迭代中工作,以增加反馈和价值流动
  • 生成系统文档,根据系统行为自动检查

发展史

瀑布开发模式

以前使用的开发模型大多都是瀑布开发模式,但是由于瀑布模型的先开发后测试的特性,导致代码交予测试后会有一大段时间代码开发人员处于空闲期,没活干,这大大的拖慢了软件开发的进度。

Go ---- godog的使用_第1张图片

test-first programing

因为在开发中可能不会按照瀑布开发模型走,而是一边写代码一边测试,开发的同时不断的对代码进行完善。这样的做法叫test-first programing

测试驱动开发

如果在测试开发的过程中发现功能没办法使用现在可用的技术实现,也将大大的降低效率,任何代码不能开发到一半的时候才发现当前的设计方案行不通。所以在设计之前,技术上要做好测试,验证这样的设计在技术上是行得通的,然后在具体着手开发。这样的做法叫 test-driven development (TDD)

行为驱动开发

在开发过程中突然发现原本的功能几乎无用,或是别的功能或许更加重要,然后再这样的代码上做出针对性的调整。这样的做法叫:behavior-driven development (BDD)

行为驱动开发就是由测试驱动开发发展来的。它遵循持续迭代,小步快跑原则。

Step

Step是指GivenWhenThenAndBut这种,虽然程序在处理的时候,并不会对这些关键字做区分,但在写feature文件的时候,我们需要做明确区分,方便我们合理的描述流程。

结合文章开头的例子,可能觉得例子太过于简单了。但实际上这个gherkin语法支持的功能也是很丰富的。包括它的scenario outlinebackground等。

主要的关键字,点击查看详细信息:

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

几个常用的简单介绍

  • Feature:描述我们需要测试的功能
  • Scenario: 描述测试场景
  • Given: 描述初始上下文
  • When: 描述一个事件(强烈建议每个方案只有一个步骤)
  • Then: 描述预期结果(应基于可观察的输出)

参考信息:

GitHub - cucumber/godog: Cucumber for golang

How to use godog | 渐行渐远 (neojos.com)

你可能感兴趣的:(go学习笔记,golang,开发语言,后端)