英文:
Golang Unit Test Mock method of nested struct
问题
我想模拟一个嵌套结构体的方法。我尝试定义一个接口并让模拟对象实现它,但是我无法使其正常工作。
这是我想要测试的结构体:
type OuterThing struct {
innerThing *InnerThing
}
func (a *OuterThing) doLotsOfStuff() {
println("i am doing")
u, err := a.innerThing.DoStuff("lots of stuff")
if err != nil {
println("ran into an error, also doing some logic")
}
println("and more", u)
}
我想要模拟其DoStuff()
函数的嵌套结构体如下:
type InnerThing struct {
name string
}
func (b *InnerThing) DoStuff(x string) (uint64, error) {
println("i want to mock this method")
return 0, nil
}
小小的曲折:我不能更改这些结构体及其方法的代码。
为了更清楚地表达我的观点,我编写了以下测试:
func TestDoLotsOfStuff(t *testing.T) {
testCases := []struct {
name string
structUnderTest *OuterThing
}{
{
name: "happy case",
structUnderTest: &OuterThing{
innerThing: &InnerThing{name: "I am the inner thing."},
},
},
{
name: "error case",
structUnderTest: &OuterThing{
innerThing: &InnerThing{name: "i should be a mock with a mocked DoStuff function"},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
testCase.structUnderTest.doLotsOfStuff()
// assertions
})
}
}
我对Java和Mockito非常熟悉,这将是一个相当简单的任务。我知道Go语言在隐式接口和没有类等方面有很多不同,但这真的是一个如此罕见的用例吗?
英文:
I want to mock a method of a nested struct. I have tried to define an interface and make the Mock implement it, but I could not get it working.
This is the struct I want to test:
type OuterThing struct {
innerThing *InnerThing
}
func (a *OuterThing) doLotsOfStuff() {
println("i am doing")
u, err := a.innerThing.DoStuff("lots of stuff")
if err != nil {
println("ran into an error, also doing some logic")
}
println("and more", u)
}
The nested struct, of which I want to mock its DoStuff()
function, looks like this:
type InnerThing struct {
name string
}
func (b *InnerThing) DoStuff(x string) (uint64, error) {
println("i want to mock this method")
return 0, nil
}
Little side twist: I can not change the code of these structs and their methods.
To make my point a bit more clear i have written this test:
func TestDoLotsOfStuff(t *testing.T) {
testCases := []struct {
name string
structUnderTest *OuterThing
}{
{
name: "happy case",
structUnderTest: &OuterThing{
innerThing: &InnerThing{name: "I am the inner thing."},
},
},
{
name: "error case",
structUnderTest: &OuterThing{
innerThing: &InnerThing{name: "i should be a mock with a mocked DoStuff function"},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
testCase.structUnderTest.doLotsOfStuff()
// assertions
})
}
}
I am quite familiar with Java and Mockito and this would be a pretty trivial task. I know Go has lots of differences with its implicit interfaces and no classes et cetera, but is this really such an uncommon usecase?
答案1
得分: 2
你可以通过使用接口和依赖注入来实现。假设你有一个名为Inner
的接口,其中包含DoStuff()
方法。OuterThing
结构体应该包含这个接口,而不是InnerThing
结构体。现在,你可以使用依赖注入将Inner
接口传递给OuterThing
结构体。
type Inner interface {
DoStuff(string) (uint64, error)
}
type OuterThing struct {
innerThing Inner
}
func NewOuterThing(in Inner) *OuterThing {
return &OuterThing{
innerThing: in,
}
}
现在,在测试中,你可以创建mockInnerThing
结构体并实现模拟的DoStuff()
方法,然后将mockInnerThing
传递给OuterThing
结构体。
type MockInnerThing struct {
name string
}
func NewMockInnerThing(name string) *MockInnerThing {
return &MockInnerThing{
name: name,
}
}
func (b *MockInnerThing) DoStuff(x string) (uint64, error) {
println("Mock!")
return 0, nil
}
func TestDoLotsOfStuff(t *testing.T) {
mit := NewMockInnerThing("Test")
ot := NewOuterThing(mit)
ot.doLotsOfStuff()
}
英文:
You can do it by using an Interface and Dependency Injection.
Let's say, you have an Interface called Inner
that contains the DoStuff()
method. The OuterThing
struct should contain this Interface instead of the struct InnerThing
. Now, you can use dependency injection to pass the Inner
Interface to this OuterThing
struct.
type Inner interface {
DoStuff(string) (uint64, error)
}
type OuterThing struct {
innerThing Inner
}
func NewOuterThing(in Inner) *OuterThing {
return &OuterThing{
innerThing: in,
}
}
Now, in the test, you can create the mockInnerThing
struct and implement the mock DoStuff()
method and pass the mockInnerThing
to the OuterThing
struct.
type MockInnerThing struct {
name string
}
func NewMockInnerThing(name string) *MockInnerThing {
return &MockInnerThing{
name: name,
}
}
func (b *MockInnerThing) DoStuff(x string) (uint64, error) {
println("Mock!")
return 0, nil
}
func TestDoLotsOfStuff(t *testing.T) {
mit := NewMockInnerThing("Test")
ot := NewOuterThing(mit)
ot.doLotsOfStuff()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论