使用 testify 模拟接口方法两次,输入和输出不同

Rie*_*ana 2 unit-testing go testify

如何在 golang 测试中模拟接口方法两次?例如:

type myCache interface{
    Get(key string, data interface{}) error
}

type service struct {
    cache myCache
}

func (s service) GetBookDetail() (BookDetail, error) {
    ...
    book := Book{}
    err := s.cache.Get("book", &book)
    if err != nil {
        return BookDetail{}, err
    }
    ...
    author := Author{}
    err := s.cache.Get("author", &author)
    if err != nil {
        return BookDetail{}, err
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

当我测试时func GetBookDetail(),我怎样才能模拟Get(key string, data interface{}) error两次?我尝试这样做但失败了:

func TestGetBookDetail(t *testing.T) {
    ...

    mockCache.On("Get",
        mock.MatchedBy(func(key string) bool {
            return key == "book"
        }), mock.MatchedBy(func(data interface{}) bool {
            return data == &Book{}
        })).Return(nil)

    mockCache.On("Get",
        mock.MatchedBy(func(key string) bool {
            return key == "author"
        }), mock.MatchedBy(func(data interface{}) bool {
            return data == &Author{}
        })).Return(nil)
    ...
    out, err := mockService.GetBookDetail()
    ...
}
Run Code Online (Sandbox Code Playgroud)

测试时出现这样的错误:

差异:

0: PASS: (string=book) 与 func(string) bool 匹配

1:失败:(*Book=&{ }) 与 func() bool 不匹配 [已恢复]

恐慌:

注:我用的是github.com/stretchr/testify

小智 6

首先,回答您的问题:是的,您可以指定要返回一个值与另一个值的次数。您可以使用Once()Twice()或来完成此操作Times(n),如下所示:

m.On("foo", ...).Return(...).Once()
Run Code Online (Sandbox Code Playgroud)

另外,在测试结束时,您应该通过执行 来确认这些方法被调用了正确的次数m.AssertExpectations(t)

现在,我的建议是:看来你的模拟过于复杂化了。mock.MatchedBy仅当您希望检查部分相等或在检查相等之前进行一些处理时才需要使用。在你的情况下,m.On("Get", "book", &Book{})...应该工作得很好。

另外,由于您对模拟函数有不同的“输入” - 您不一定需要Once()在末尾添加。仅当您想要返回不同的值但参数保持相同时,它才变得强制。然而,断言该函数是否被调用了预期的次数是一个很好的做法。