首页 > 解决方案 > 使用接口进行模拟以进行测试

问题描述

我对 Go 很陌生,而且我来自 OOP 语言。现在,接口和类的概念似乎完全不同。

我想知道在测试的情况下模拟将如何工作。我的困惑是是否可以struct用作一个类,如果下面的方法是你想怎么做的?假设这DefaultArticlesRepository将用于真实数据并MockArticlesRepository用于模拟它。

type ArticlesRepository interface {
    GetArticleSections() []ArticleSectionResponse
}

type DefaultArticlesRepository struct{}
type MockArticlesRepository struct{}

func (repository DefaultArticlesRepository) GetArticleSections() []ArticleSectionResponse {
    return []ArticleSectionResponse{
        {
            Title: "Default response",
            Tag:   "Default Tag",
        },
    }
}

func (repository MockArticlesRepository) GetArticleSections() []ArticleSectionResponse {
    return []ArticleSectionResponse{
        {
            Title: "Mock response",
            Tag:   "Mock Tag",
        },
    }
}

func ArticleSectionsProvider(v ArticlesRepository) ArticlesRepository {
    return v
}

func TestFoo(t *testing.T) {
    realProvider := ArticleSectionsProvider(DefaultArticlesRepository{})
    mockProvider := ArticleSectionsProvider(MockArticlesRepository{})

    assert.Equal(t, realProvider.GetArticleSections(), []ArticleSectionResponse{
        {
            Title: "Default response",
            Tag:   "Default Tag",
        },
    })

    assert.Equal(t, mockProvider.GetArticleSections(), []ArticleSectionResponse{
        {
            Title: "Mock response",
            Tag:   "Mock Tag",
        },
    })
}

标签: unit-testinggogo-testing

解决方案


首先,我建议您使用https://github.com/vektra/mockery根据接口自动生成模拟结构。实现一个像你这样的模拟结构是可以的,但我认为如果你真的不需要该结构的非常特殊的行为,那只会浪费你的时间和精力。

其次,我们不需要像您在代码中那样测试模拟结构。

assert.Equal(t, mockProvider.GetArticleSections(), []ArticleSectionResponse{
    {
        Title: "Mock response",
        Tag:   "Mock Tag",
    },
})

因此,当我们使用模拟结构时,假设 struct a是 struct b的依赖项。例如:

type A interface {
    DoTask() bool
} 

type a struct {}

func (sa *a) DoTask() bool {
    return true
}

type b struct {
    a A
}

func (sb *b) DoSomething() bool {
    //Do some logic
    sb.a.DoTask();
    //Do some logic
    return true;
}

并且您想测试 struct b的功能 DoSomething 。当然,在这种情况下,您不关心也不想测试 struct a的函数 DoTask。然后,您只需在测试中提供 struct a到 struct b的模拟。这个模拟还可以帮助您避免在测试 struct b时处理与 struct a相关的任何问题。现在你的测试应该是这样的:

func (s *TestSuiteOfStructB) TestDoSomething_NoError() {
    //Suppose that mockedOfA  is a mock of struct a
    instanceOfB := b{a: mockedOfA}
    mockedOfA.On("DoTask").Return(true)
    actualResult := instanceOfB.DoSomething()
    s.Equal(true, actualResult)
}

最后,这只是一件小事,但看不到您的ArticleSectionsProvider的明确责任。


推荐阅读