[Day 24] BDD - godog 小试身手

godog 简介

godog是Cucumber官方的Golang BDD(Behaviour-Driven Development)框架,它将规范和测试文件二合一,使用 Gherkin 格式的场景,格式为 Given, When, Then。

这里我就不再介绍BDD罗~

怎麽用

godog 起手式

设定go module

建立一个资料夹 - mkdir godogs

进入资料夹内 - cd godogs

go mod init godog - go mod init godogs

安装 godog

安装godog执行档 - go get github.com/cucumber/godog/cmd/godog

建立一个 gherkin feature档

建立一个features资料夹 - mkdir features

建立godogs.feature 里面描述要测试的行爲特徵 - vi features/godogs.feature

以下是我的范例

Feature: write ithome30days
  As a happy contestant 

  Scenario: Write 5 out of 30
    Given there are 30 days
    When I write 5
    Then there should be 25 remaining

建立step definitions

执行godog

执行godog run
Feature: write ithome30days
  As a happy contestant

  Scenario: Write 5 out of 30         # features/godogs.feature:4
    Given there are 30 days
    When I write 5
    Then there should be 25 remaining # godogs_test.go:14 -> thereShouldBeRemaining

1 scenarios (1 undefined)
3 steps (2 undefined, 1 skipped)
455.835µs

You can implement step definitions for undefined steps with these snippets:

func iWrite(arg1 int) error {
        return godog.ErrPending
}

func thereAreDays(arg1 int) error {
        return godog.ErrPending
}

func thereShouldBeRemaining(arg1 int) error {
        return godog.ErrPending
}

func InitializeScenario(ctx *godog.ScenarioContext) {
        ctx.Step(`^I write (\d+)$`, iWrite)
        ctx.Step(`^there are (\d+) days$`, thereAreDays)
        ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}

然後建个测试档案,再把刚刚那些未定义的func复制到新的档案中 - vi godogs_test.go

package main

import "github.com/cucumber/godog"

func iWrite(arg1 int) error {
	return godog.ErrPending
}

func thereAreDays(arg1 int) error {
	return godog.ErrPending
}

func thereShouldBeRemaining(arg1 int) error {
	return godog.ErrPending
}

func InitializeScenario(ctx *godog.ScenarioContext) {
	ctx.Step(`^I write (\d+)$`, iWrite)
	ctx.Step(`^there are (\d+) days$`, thereAreDays)
	ctx.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}

目前我们的目录结构长这样

godogs
- features
  - godogs.feature
- go.mod
- go.sum
- godogs_test.go

再执行一次godog - godog

您可以看到该场景处於待pending状态,其中一个步骤处於pending状态并且有两个跳过了步骤:

Feature: write ithome30days
  As a happy contestant

  Scenario: Write 5 out of 30         # features/godogs.feature:4
    Given there are 30 days           # godogs_test.go:10 -> thereAreDays
      TODO: write pending definition
    When I write 5                    # godogs_test.go:6 -> iWrite
    Then there should be 25 remaining # godogs_test.go:14 -> thereShouldBeRemaining

1 scenarios (1 pending)
3 steps (1 pending, 2 skipped)
259.906µs

你可以直接把 return godog.ErrPending 改为 return nil 让场景测试成功通过

建立一个要被测试的go档

建立一个godogs.go档案并将当作main - vi godogs.go

package main

// Godogs available to eat
var Godogs int

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

目前我们的目录结构长这样

godogs
- features
  - godogs.feature
- go.mod
- go.sum
- godogs.go
- godogs_test.go

向我们的定义加上一些小逻辑

让我们实现步骤的定义,来测试我们的功能需求:

调整一下 godogs_test.go 内容。

package main

import (
	"context"
	"fmt"

	"github.com/cucumber/godog"
)

func thereAreGodogs(available int) error {
	Godogs = available
	return nil
}

func iEat(num int) error {
	if Godogs < num {
		return fmt.Errorf("you cannot eat %d godogs, there are %d available", num, Godogs)
	}
	Godogs -= num
	return nil
}

func thereShouldBeRemaining(remaining int) error {
	if Godogs != remaining {
		return fmt.Errorf("expected %d godogs to be remaining, but there is %d", remaining, Godogs)
	}
	return nil
}

func InitializeTestSuite(sc *godog.TestSuiteContext) {
	sc.BeforeSuite(func() { Godogs = 0 })
}

func InitializeScenario(sc *godog.ScenarioContext) {
	sc.Before(func(ctx context.Context, sc *godog.Scenario) (context.Context, error) {
		Godogs = 0 // clean the state before every scenario

		return ctx, nil
	})

	sc.Step(`^there are (\d+) godogs$`, thereAreGodogs)
	sc.Step(`^I eat (\d+)$`, iEat)
	sc.Step(`^there should be (\d+) remaining$`, thereShouldBeRemaining)
}

让我们再次执行 godog

Feature: write ithome30days
  As a happy contestant

  Scenario: Write 5 out of 30         # features/godogs.feature:4
    Given there are 30 days           # godogs_test.go:21 -> thereAreDays
    When I write 5                    # godogs_test.go:10 -> iWrite
    Then there should be 25 remaining # godogs_test.go:25 -> thereShouldBeRemaining
1 scenarios (1 passed)
3 steps (3 passed)
326.79µs

以上基本就完成一个godog BDD的简易流程罗。


<<:  [NestJS 带你飞!] DAY17 - Injection Scopes

>>:  Day 18 urllib模组

从零开始的8-bit迷宫探险【Level 3】Swift 基础语法 (一)

今日目标 认识变数及常数 认识型态:字元、字串、整数、浮点数、布林值 变数 宣告一个变数可以使用 v...

资安学习路上-网站常见漏洞与 Injection的爱恨情仇3

资料库类型补充 1. SQL 资料库 结构化查询语言(Structured Query Langua...

KSP 的实作方向

这系列的文章不会讲完全部 KSP 的实作,毕竟我也还正在实作中,不过实作的方向应该是跟前几篇讲的差不...

<Day17>在用API做投资前,先弄懂什麽是"量化交易"?

● 让我们来一起探究什麽是"量化交易"吧! 说到"反覆验证"...

[ Day 24 ] - 阵列资料处理 - filter

特性与用途 不会影响到原始阵列的资料 可以筛选符合条件的内容,并且回传至新的阵列 直接进入写法及范例...