如何正确测试依赖项

如何正确测试依赖项

问题描述:

In Go, how would I test that a mock dependency has been called in the correct way.

If I have a struct that takes a interface for a dependency, after injection I want to be able to test the original mock object has been called.

My current code in this example I can not see that the struct value has changed. If I change my code to pass by reference it triggers the error:

s.simpleInterface.Call undefined (type *SimpleInterface is pointer to interface, not interface)

type SimpleInterface interface {
    Call()
}

type Simple struct {
    simpleInterface SimpleInterface
}

func (s Simple) CallInterface() {
    s.simpleInterface.Call()
}

type MockSimple struct {
    hasBeenCalled bool
}

func (ms MockSimple) Call() {
    ms.hasBeenCalled = true
}

func TestMockCalled(t *testing.T) {
    ms := MockSimple{}
    s := Simple{
        simpleInterface: ms,
    }
    s.CallInterface()

    if ms.hasBeenCalled != true {
        t.Error("Interface has not been called")
    }
}

在Go中,我将如何测试是否以正确的方式调用了模拟依赖项。 p> \ n

如果我有一个采用依赖关系接口的结构,则在注入后,我希望能够测试原始的模拟对象。 p>

我当前的代码 在此示例中,我看不到结构值已更改。 如果我更改代码以通过引用传递,则会触发错误: p>

s.simpleInterface.Call未定义(类型* SimpleInterface是指向接口的指针,而不是接口) em> p>

  type SimpleInterface接口{
 Call()
} 
 
type Simple struct {
 simpleInterface SimpleInterface 
} 
 
func(s Simple)CallInterface(  ){
 s.simpleInterface.Call()
} 
 
type MockSimple struct {
 hasBeenCalled bool 
} 
 
func(ms MockSimple)Call(){
 ms.hasBeenCalled = true 
}  
 
func TestMockCalled(t * testing.T){
 ms:= MockSimple {} 
s:=简单{
 simpleInterface:ms,
} 
 s.CallInterface()
 
如果是ms。  hasBeenCalled!= true {
 t.Error(“尚未调用接口”)
} 
} 
  code>  pre> 
  div>

I see three easy ways to fix this:

1- Change the signature of the Call method to receive a pointer to MockSimple, and when instantiating the Simple struct, give it the address of your mock:

func (ms *MockSimple) Call() {
    ms.hasBeenCalled = true
}

func TestMockCalled(t *testing.T) {
    ms := MockSimple{}
    s := Simple{
        simpleInterface: &ms,
    }
    s.CallInterface()

    if ms.hasBeenCalled != true {
        t.Error("Interface has not been called")
    }
}

2- Not the cleanest solution, but still works. Use it if you really cant use #1. Declare "hasBeenCalled" somewhere else and change your MockSimple to hold a pointer to it:

type MockSimple struct {
    hasBeenCalled *bool
}

func (ms MockSimple) Call() {
    *ms.hasBeenCalled = true
}

func TestMockCalled(t *testing.T) {
    hasBeenCalled := false
    ms := MockSimple{&hasBeenCalled}
    s := Simple{
        simpleInterface: ms,
    }
    s.CallInterface()

    if hasBeenCalled != true {
        t.Error("Interface has not been called")
    }
}

3- Probably a really bad solution: using globals, so I would only use it as a last resort (always avoid global state). Make "hasBeenCalled" a global and modify it from the method.

var hasBeenCalled bool

type MockSimple struct{}

func (ms MockSimple) Call() {
    hasBeenCalled = true
}

func TestMockCalled(t *testing.T) {
    ms := MockSimple{}
    s := Simple{
        simpleInterface: ms,
    }
    s.CallInterface()

    if hasBeenCalled != true {
        t.Error("Interface has not been called")
    }
}

Cheers!