iT邦幫忙

2021 iThome 鐵人賽

DAY 24
0
DevOps

Dev's Ops 啟程系列 第 24

[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的簡易流程囉。


上一篇
[Day 23] Mattermost - ChatOps
下一篇
[Day 25] BDD - godog image封裝
系列文
Dev's Ops 啟程30

尚未有邦友留言

立即登入留言