Go ---- godog的使用

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

有以下几个特点:

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

发展史

瀑布开发模式

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

test-first programing

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

测试驱动开发

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

行为驱动开发

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

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

Step

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

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

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

几个常用的简单介绍

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

参考信息:

GitHub - cucumber/godog: Cucumber for golang

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



相关文章
|
22天前
|
Go
go select 使用总结
go select 使用总结
22 1
|
2月前
|
Go
go之select
go之select
19 0
|
存储 数据采集 XML
GO中 gjson 的应用和分享
咱们上次分享到使用 GO 爬取静态网页的数据,一起来回顾一下 • 分享静态网页和动态网页的简要说明 • GO 爬取静态网页简单数据 • GO 爬取网页上的图片 • 并发爬取网页上的资源
GO中 gjson 的应用和分享
|
12月前
|
Java Go
Go的forcegc
go中的强制垃圾回收
76 0
|
存储 搜索推荐 编译器
Go源码解析之select.go
Go源码解析之select.go
83 0
|
存储 JSON 安全
关于Go你不得不知道的小技巧2
关于Go你不得不知道的小技巧2
89 0
|
存储 设计模式 网络协议
|
网络协议 视频直播 Go
go里的select特点|Go主题月
在go中有一个类似switch的关键字,那就是select。 select的每个case接收的是I/O通讯操作,不能有其他表达式。select要配合channel使用。
114 0
|
缓存 安全 Java
Go---Go并发编程(详细)(二)
Go---Go并发编程(详细)