golang YATSPEC风格BDD测试框架插件gogiven的使用
golang YATSPEC风格BDD测试框架插件gogiven的使用
gogiven是一个基于"go test"工具和go testing包的替代BDD规范框架。
介绍
Go Givens是一个轻量级的BDD框架,用于直接从您编写的代码生成测试规范。它会解析您的测试文件并生成人类可读的输出,包含所有测试、捕获的数据以及与测试相关的其他信息,如成功或失败。
Go Givens受到YATSPEC的启发,YATSPEC是英国电视公司Sky的网络服务部门广泛使用的BDD框架。
为什么使用它?
在BDD中,系统的输入和输出对业务很重要。捕获数据与系统处理方式之间的关系可以向客户展示。例如,您的系统可能调用第三方服务,您可能希望用存根来建模交互。
示例代码
import (
"github.com/corbym/gocrest/has"
"github.com/corbym/gocrest/then"
"github.com/corbym/gogiven/base"
"github.com/corbym/gogiven/testdata"
"testing"
"github.com/corbym/gocrest/is"
)
func TestMain(testmain *testing.M) {
runOutput := testmain.Run()
GenerateTestOutput() // 如果您想生成HTML输出,只需要在test main中调用GenerateTestOutput()
os.Exit(runOutput)
}
func TestMyFirst(testing *testing.T) {
Given(testing, someDataSetup).
When(somethingHappens).
Then(func(testing base.TestingT, actual testdata.CapturedIO, givens testdata.InterestingGivens) { // 传入的testing应该用于断言
// 执行断言
then.AssertThat(testing, actual["actual"], is.EqualTo("some output"))
})
}
注意您不必使用"gocrest"断言,您仍然可以调用testing.T的所有函数来使测试失败,或者您可以使用任何与testing.T兼容的go测试断言包。
表格测试示例
表格测试的工作方式与普通的go表格测试相同。GoGivens会在您的测试输出中标记哪些测试失败了。
func TestMyFirst(testing *testing.T){
var someRange = []struct {
actual string
expected int
}{
{actual: "", expected: 0},
{actual: "a", expected: 2},
}
for _, test := range someRange {
tst.Run(test.actual, func(weAreTesting *testing.T) {
Given(weAreTesting, someDataSetup).
When(someAction).
Then(func(t TestingT, actual CapturedIO, givens InterestingGivens) {
// 执行断言
AssertThat(t, actual.CapturedIO["actual"], is.EqualTo("some output"))
})
}
}
}
内容生成
Gogivens默认配置了一个HTML生成器(htmlspec.NewTestOutputGenerator
),由文件生成器(generator.FileOutputGenerator
)使用。内容生成器实现以下接口:
type GoGivensOutputGenerator interface {
Generate(data *PageData) (output io.Reader)
//ContentType是text/html、application/json或其他mime类型
ContentType() string
}
生成的内容(output io.Reader)
然后由OutputListener使用:
type OutputListener interface {
Notify(testFilePath string, contentType string, output io.Reader)
}
如果您想要自己的输出监听器,只需创建自己的监听器,并在TestMain中替换和/或附加到默认监听器:
func TestMain(testmain *testing.M) {
gogiven.OutputListeners = []generator.OutputListener{new(MyFooListener)}
// 或者也可以(或者同时!)
gogiven.OutputListeners = append(OutputListeners, new(MyBarListener))
runOutput := testmain.Run()
gogiven.GenerateTestOutput() // 在测试完成后生成输出
os.Exit(runOutput)
}
设置测试文件输出(对于generator.FileOutputGenerator
)
您可以添加环境变量GOGIVENS_OUTPUT_DIR到您的环境属性中,指向您希望goGivens报告测试输出的目录。
默认是操作系统的tmp目录。
预编写的输出生成器列表
GoGiven附带以下输出生成器:
- HTML Spec: 生成测试示例中使用的输出
- JSON Spec: 以JSON格式生成输出
更多关于golang YATSPEC风格BDD测试框架插件gogiven的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang YATSPEC风格BDD测试框架插件gogiven的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用gogiven实现YATSPEC风格的BDD测试
gogiven是一个Go语言的BDD测试框架,它采用了类似YATSPEC的Given-When-Then风格来编写测试用例。下面我将介绍如何使用gogiven框架编写行为驱动开发(BDD)风格的测试。
安装gogiven
首先安装gogiven包:
go get github.com/corbym/gogiven
基本用法示例
下面是一个简单的gogiven测试示例:
package example
import (
"testing"
"github.com/corbym/gogiven"
. "github.com/corbym/gogiven/base"
)
func TestAddition(t *testing.T) {
gogiven.Given(t, someTestContextSetup).
When(func(testContext TestContext, when When) {
// 执行操作
result := add(2, 3)
when.Result = result
}).
Then(func(testContext TestContext, then Then) {
// 验证结果
then.Expect("result should be 5").
ThatInt(testContext.Result().(int)).
IsEqualTo(5)
})
}
func someTestContextSetup(testContext TestContext) {
// 测试前的初始化设置
testContext.Title("Addition Test")
}
func add(a, b int) int {
return a + b
}
关键组件说明
- Given: 设置测试的初始状态和上下文
- When: 执行被测操作
- Then: 验证结果是否符合预期
更复杂的示例
下面是一个更完整的示例,展示更多gogiven的功能:
package shoppingcart
import (
"testing"
"github.com/corbym/gogiven"
. "github.com/corbym/gogiven/base"
)
type ShoppingCart struct {
items map[string]int
total int
}
func TestShoppingCart(t *testing.T) {
gogiven.Given(t, func(testContext TestContext) {
testContext.Title("Shopping Cart Test")
testContext.Given("an empty shopping cart", func(given Given) {
cart := &ShoppingCart{
items: make(map[string]int),
total: 0,
}
given.Value("cart", cart)
})
}).
When(func(testContext TestContext, when When) {
cart := testContext.Value("cart").(*ShoppingCart)
cart.items["apple"] = 2
cart.items["banana"] = 3
cart.total = 5
}).
Then(func(testContext TestContext, then Then) {
cart := testContext.Value("cart").(*ShoppingCart)
then.Expect("cart should have 2 apples").
ThatInt(cart.items["apple"]).
IsEqualTo(2)
then.Expect("cart should have 3 bananas").
ThatInt(cart.items["banana"]).
IsEqualTo(3)
then.Expect("total items should be 5").
ThatInt(cart.total).
IsEqualTo(5)
})
}
高级特性
- 表格驱动测试:
func TestTableDrivenAddition(t *testing.T) {
testCases := []struct {
a, b, expected int
}{
{1, 1, 2},
{2, 3, 5},
{0, 0, 0},
{-1, 1, 0},
}
for _, tc := range testCases {
gogiven.Given(t, func(testContext TestContext) {
testContext.Title("Addition of %d and %d", tc.a, tc.b)
}).
When(func(testContext TestContext, when When) {
when.Result = add(tc.a, tc.b)
}).
Then(func(testContext TestContext, then Then) {
then.Expect("result should be %d", tc.expected).
ThatInt(testContext.Result().(int)).
IsEqualTo(tc.expected)
})
}
}
- 异步测试:
func TestAsyncOperation(t *testing.T) {
gogiven.Given(t, nil).
When(func(testContext TestContext, when When) {
done := make(chan bool)
go func() {
// 模拟异步操作
time.Sleep(100 * time.Millisecond)
when.Result = 42
done <- true
}()
<-done
}).
Then(func(testContext TestContext, then Then) {
then.Expect("async result should be 42").
ThatInt(testContext.Result().(int)).
IsEqualTo(42)
})
}
生成HTML报告
gogiven可以生成漂亮的HTML测试报告:
func TestMain(m *testing.M) {
// 配置HTML报告生成
gogiven.GenerateTestOutput()
os.Exit(m.Run())
}
运行测试后,会在目录下生成testoutput
文件夹,包含HTML格式的测试报告。
最佳实践
- 保持Given-When-Then各部分职责单一
- 使用有意义的测试标题和期望描述
- 对于复杂场景,可以拆分多个Given块
- 利用表格驱动测试覆盖多种情况
- 合理使用HTML报告分析测试结果
gogiven框架通过其YATSPEC风格的语法,使得Go语言测试代码更加易读和易于维护,特别适合团队协作和复杂业务逻辑的测试。