I'm pretty new with Go, and I'm coming from OOP languages. Now the concept seems quite different in go of interfaces and classes.
I was wondering how mocking would work in case of testing. The confusion I'm having is whether ok to use struct
as a classes and if the approach below is how you suppose to do? Assuming that DefaultArticlesRepository
would be for real data and MockArticlesRepository
for mocking it.
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",
},
})
}
Firstly, I suggest you to use https://github.com/vektra/mockery for generating mock structs automatically based on interfaces. Implementing a mock struct like your is ok but I think it just wastes your time and effort if you do not really need a very special behavior for that struct.
Secondly, we do not need to test mock structs like you do in your code.
assert.Equal(t, mockProvider.GetArticleSections(), []ArticleSectionResponse{
{
Title: "Mock response",
Tag: "Mock Tag",
},
})
So when we use mock structs, suppose struct a is a dependency of struct b. For example:
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;
}
And you want to test function DoSomething of struct b. Of course you do not care and do not want to test function DoTask of struct a in this case. Then you just simply provide a mock of struct a to struct b in the test. This mock also helps you avoid to deal with any struggle related to struct a in testing struct b. Now your test should be like this:
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)
}
The last, this is just a small thing but do not see a clear responsibility of your ArticleSectionsProvider.