将断言库与 GoDog 测试框架一起使用
Using an assertion library with GoDog test framework
我正在使用 Cucumber GoDog 作为 gRPC 微服务测试的 BDD 测试框架。 GoDog 不附带任何断言助手或实用程序。
这里有没有人有在 GoDog 中采用任何现有断言库的经验,例如 Testify/GoMega?
据我所知,GoDog 不能在 go test
之上工作,这就是为什么我认为像我提到的那样采用任何基于 go test
的断言库都具有挑战性。不过还是想看看有没有人有这方面的经验
很抱歉看到您仍在为此努力。
正如我们之前聊过的那样,是一种通过我之前发给你的the link让它工作的方法,它不一定像你提到的那样适合初学者在松弛。也许这是我们的贡献者将来可以考虑的事情,只是目前还没有设置,而且由于我们主要是志愿者,因此为新功能设置时间表可能很困难。
我目前的建议是通过 if 语句进行断言。如果您不想在您的测试代码中专门使用它们,那么您可以制作一个快速包装函数并以这种方式调用它们。
这是使用 Testify 的基本概念验证:
package bdd
import (
"fmt"
"github.com/cucumber/godog"
"github.com/stretchr/testify/assert"
)
type scenario struct{}
func (_ *scenario) assert(a assertion, expected, actual interface{}, msgAndArgs ...interface{}) error {
var t asserter
a(&t, expected, actual, msgAndArgs...)
return t.err
}
func (sc *scenario) forcedFailure() error {
return sc.assert(assert.Equal, 1, 2)
}
type assertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool
type asserter struct {
err error
}
func (a *asserter) Errorf(format string, args ...interface{}) {
a.err = fmt.Errorf(format, args...)
}
func FeatureContext(s *godog.Suite) {
var sc scenario
s.Step("^forced failure$", sc.forcedFailure)
}
Feature: forced failure
Scenario: fail
Then forced failure
这里的关键是实现 Testify 的 assert.TestingT
接口。
这是 GoMega 的概念证明:
在 运行 任何测试之前注册 GoMega 失败处理程序,让 GoMega 简单地恐慌并显示错误消息。
gomega.RegisterFailHandler(func(message string, _ ...int) {
panic(message)
})
定义步骤失败处理程序以从任何失败中恢复。
func failHandler(err *error) {
if r := recover(); r != nil {
*err = fmt.Errorf("%s", r)
}
}
现在在每个步骤定义的开头延迟 运行 像这样设置 failHandler:
func shouldBeBar(foo string) (err error) {
defer failHandler(&err)
Expect(foo).Should(Equal("bar"))
return err
}
现在 if/when 我们的第一个 GoMega 断言失败,step 函数将 运行 failHandler 和 return GoMega 失败消息(如果有的话)。请注意,我们正在使用命名结果参数来 return 错误,请参阅
今天有同样的问题,试图将gomega与godog集成。由于 Go 的简单性,我设法让一些东西工作(这是我使用 Go 的第三天 :-)。尽管我认为这在现实世界的项目中行不通,但我还是想分享一下我的想法。
来自 Rails/RSpec,我喜欢没有样板代码的紧凑测试 cases/steps。所以我试着把处理失败的步骤放到 before/after 钩子中:
func InitializeGomegaForGodog(ctx *godog.ScenarioContext) {
var testResult error
ctx.StepContext().Before(func(ctx context.Context, st *godog.Step) (context.Context, error) {
testResult = nil
return ctx, nil
})
ctx.StepContext().After(func(ctx context.Context, st *godog.Step, status godog.StepResultStatus, err error) (context.Context, error) {
return ctx, testResult
})
gomega.RegisterFailHandler(func(message string, callerSkip ...int) {
// remember only the expectation failed first
// anything thereafter is not to be believed
if testResult == nil {
testResult = fmt.Errorf(message)
}
})
}
func InitializeScenario(ctx *godog.ScenarioContext) {
InitializeGomegaForGodog(ctx)
ctx.Step(`^incrementing (\d+)$`, incrementing)
ctx.Step(`^result is (\d+)$`, resultIs)
}
当然,这种方法不会停止与预期不符的步骤。因此,在步骤的其余部分存在未定义行为的风险。但是使用这种方法,步骤的实现非常简单:
func resultIs(arg1 int) {
gomega.Expect(1000).To(gomega.Equal(arg1))
}
我正在使用 Cucumber GoDog 作为 gRPC 微服务测试的 BDD 测试框架。 GoDog 不附带任何断言助手或实用程序。
这里有没有人有在 GoDog 中采用任何现有断言库的经验,例如 Testify/GoMega?
据我所知,GoDog 不能在 go test
之上工作,这就是为什么我认为像我提到的那样采用任何基于 go test
的断言库都具有挑战性。不过还是想看看有没有人有这方面的经验
很抱歉看到您仍在为此努力。
正如我们之前聊过的那样,是一种通过我之前发给你的the link让它工作的方法,它不一定像你提到的那样适合初学者在松弛。也许这是我们的贡献者将来可以考虑的事情,只是目前还没有设置,而且由于我们主要是志愿者,因此为新功能设置时间表可能很困难。
我目前的建议是通过 if 语句进行断言。如果您不想在您的测试代码中专门使用它们,那么您可以制作一个快速包装函数并以这种方式调用它们。
这是使用 Testify 的基本概念验证:
package bdd
import (
"fmt"
"github.com/cucumber/godog"
"github.com/stretchr/testify/assert"
)
type scenario struct{}
func (_ *scenario) assert(a assertion, expected, actual interface{}, msgAndArgs ...interface{}) error {
var t asserter
a(&t, expected, actual, msgAndArgs...)
return t.err
}
func (sc *scenario) forcedFailure() error {
return sc.assert(assert.Equal, 1, 2)
}
type assertion func(t assert.TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool
type asserter struct {
err error
}
func (a *asserter) Errorf(format string, args ...interface{}) {
a.err = fmt.Errorf(format, args...)
}
func FeatureContext(s *godog.Suite) {
var sc scenario
s.Step("^forced failure$", sc.forcedFailure)
}
Feature: forced failure
Scenario: fail
Then forced failure
这里的关键是实现 Testify 的 assert.TestingT
接口。
这是 GoMega 的概念证明:
在 运行 任何测试之前注册 GoMega 失败处理程序,让 GoMega 简单地恐慌并显示错误消息。
gomega.RegisterFailHandler(func(message string, _ ...int) {
panic(message)
})
定义步骤失败处理程序以从任何失败中恢复。
func failHandler(err *error) {
if r := recover(); r != nil {
*err = fmt.Errorf("%s", r)
}
}
现在在每个步骤定义的开头延迟 运行 像这样设置 failHandler:
func shouldBeBar(foo string) (err error) {
defer failHandler(&err)
Expect(foo).Should(Equal("bar"))
return err
}
现在 if/when 我们的第一个 GoMega 断言失败,step 函数将 运行 failHandler 和 return GoMega 失败消息(如果有的话)。请注意,我们正在使用命名结果参数来 return 错误,请参阅
今天有同样的问题,试图将gomega与godog集成。由于 Go 的简单性,我设法让一些东西工作(这是我使用 Go 的第三天 :-)。尽管我认为这在现实世界的项目中行不通,但我还是想分享一下我的想法。
来自 Rails/RSpec,我喜欢没有样板代码的紧凑测试 cases/steps。所以我试着把处理失败的步骤放到 before/after 钩子中:
func InitializeGomegaForGodog(ctx *godog.ScenarioContext) {
var testResult error
ctx.StepContext().Before(func(ctx context.Context, st *godog.Step) (context.Context, error) {
testResult = nil
return ctx, nil
})
ctx.StepContext().After(func(ctx context.Context, st *godog.Step, status godog.StepResultStatus, err error) (context.Context, error) {
return ctx, testResult
})
gomega.RegisterFailHandler(func(message string, callerSkip ...int) {
// remember only the expectation failed first
// anything thereafter is not to be believed
if testResult == nil {
testResult = fmt.Errorf(message)
}
})
}
func InitializeScenario(ctx *godog.ScenarioContext) {
InitializeGomegaForGodog(ctx)
ctx.Step(`^incrementing (\d+)$`, incrementing)
ctx.Step(`^result is (\d+)$`, resultIs)
}
当然,这种方法不会停止与预期不符的步骤。因此,在步骤的其余部分存在未定义行为的风险。但是使用这种方法,步骤的实现非常简单:
func resultIs(arg1 int) {
gomega.Expect(1000).To(gomega.Equal(arg1))
}