有点像golang的初学者,但是我之前已经使用过测试框架。我该如何模拟并伪造依赖方法返回的结果而不注入依赖?我不想使用依赖项注入的原因是因为有许多外部包方法正在使用,并且将所有方法注入构造函数中都很难。
我已经搜索了此在线/堆栈溢出,解决方案是始终使用依赖项注入。有时这不是一个可行的选择。
这就是我要在代码方面做的事情:
b / b_test.go
package b
func TestResults(t *testing.T) {
t.Run("Test", func(t *testing.T) {
b := NewB()
// How do I mock out and fake a.DoSomething() to be
// "complete" instead of whats in the code right now?
result = b.Results()
assert.Equal(t, "complete", result)
}
}
b / b.go
package b
import "a"
type B struct {}
func NewB() B {
return &B{}
}
func (b B) Results() {
return a.DoSomething()
}
a / a.go
package a
func DoSomething() {
return "done"
}
谢谢!
答案 0 :(得分:5)
您可以使用conditional compilation with build tags
a / a.go
// +build !mock
package a
func DoSomething() {
return "done"
}
a / a_mock.go
// +build mock
package a
func DoSomething() { // Insert fake implementation here
return "complete"
}
$ go test -tags mock
答案 1 :(得分:3)
一种方法是使用您要调用的函数创建一个变量,因此在b.go中添加以下内容:
doSomething := func() { a.DoSomething() }
func (b B) Results() {
return a.DoSomething()
}
现在在b_test.go中,您可以执行以下操作:
func TestPrintResults(t *testing.T) {
t.Run("Test", func(t *testing.T) {
origDoSomething := doSomething
defer func() { doSomething = origDoSomething }
doSomething = func() {
// Insert fake implementation here
}
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
}
答案 2 :(得分:3)
我不确定我是否不理解您对依赖关系注入的反对,但是可以使用接口使依赖关系注入相对轻松。特别是现有代码无需修改。
您可以尝试将软件包名称别名为一个全局变量,该变量实现与外部软件包功能匹配的接口。这样做的好处是,在使用软件包“ a”的地方不需要进行内联更改。
这个想法围绕着从外部包中为您所需的功能创建接口,针对默认行为的该接口的直通实现以及用于测试的模拟实现。在测试开始时,只需将模拟变量替换为全局变量即可。
b / a_interface.go
package b
import (
aa "a" // alias the "a" package
)
// global variable that mimics the external package "a"
var a aType
// internal interface for `a` package functions (i.e. `DoSomething()`)
type aDoer interface {
DoSomething() string
}
// default implementation of the aDoer interface
type aType struct{}
func (aType) DoSomething() string {
// just pass-through to package "a"
return aa.DoSomething()
}
b / b.go-未修改,然后删除导入:
package b
type B struct{}
func NewB() B {
return B{}
}
func (b B) Results() string{
// now `a` is a global variable not a package.
return a.DoSomething()
}
b / b_test.go
package b
import (
"testing"
"github.com/stretchr/testify/assert"
)
// mock implementation of aDoer interface
type aMock struct{}
func (aMock) DoSomething() string {
return "complete"
}
func TestResults(t *testing.T) {
a = aMock{} // <- replace the default with the mock
b := NewB()
result = b.Results()
assert.Equal(t, "complete", result)
}
这有点偷偷摸摸的一面,所以您可能想对发生的事情做出明确的评论。