11

New to golang and is now researching on how to do test in golang. I see that there are popular mocking library like gomock. However, at the same time, I see that large golang open source projects don't use any mocking library at all. For example, geth (ETH miner), wire (dependency injection library) and sendgrid go client (for sending email) all choose not to use any mocking library.

Considering the fact that there is no class in golang, is it a practice that not to mock interface (which most mocking library did)? Should I just make the function to be tested as package variable and overwrite in test instead?

cytsunny
  • 627
  • 6
  • 19
  • For those who down vote this question, may I know the reason? I may update the question or move the question to other StackExchange, or close the question if it is necessary. – cytsunny Jan 15 '21 at 08:34
  • I think the lack of generics in golang is a major reason; the mocking libraries are a bit cumbersome without that ability. – Brannon Jul 26 '21 at 19:28

1 Answers1

4

The approach that mostly used in test other than mock is fake --- fakes are merely structs that fit an interface and are a form of dependency injection where the consumers control the behavior. Some distinctions based on their definitions are discussed in this post.

is it a practice that not to mock interface

I'm not sure if there is such a practice, because otherwise there won't be mock libraries at all.

However, there are tradeoff between fakes and mocks regardless of language.

  • Mocks increase coupling, and coupling makes refactoring harder (ref), while fakes decrease such coupling.
  • (ref) Mocks are assuming the client library is implemented right, and are assuming we know how the library actually behaves. As a result, mocking the library only mocks assumptions and the test is subject to change when the code is updated.
  • While fakes have the real implementation of the interface, its most use case is to test how the code is handling errors properly, and it can't test any implementation logic (code path, expected output, argument validation, ..etc) inside. So we still use mock to verify an object returns a value that is set to the tested class, at the same time use Stub to mimic an Interface or Abstract class to be tested.

Should I just make the function to be tested

Functions are generally not mockable. To address this issue, we could either

  • Implement a certain interface that the function is allowed to pass into to test the different branches of code. An code example from this post (note this is fake test):
package a

type DoSomethingInterface interface {
    DoSomething() error
}


func DoSomething(a DoSomethingInterface) {
    if err := a.DoSomething(); err != nil {
        fmt.Println("error occurred")
        return
    }
    fmt.Println("no error occurred")
    return
}

package a_test

import (
    "testing"
    "<path to a>/a"
)

type simpleMock struct {
    err error
}

func (m *simpleMock) DoSomething() error {
    return m.err
}

func TestDoSomething(t *testing.T) {
    errorMock := &simpleMock{errors.New("some error")}
    a.DoSomething(errorMock)
    // test that "an error occurred" is logged

    regularMock := &simpleMock{}
    a.DoSomething(regularMock)
    // test "no error occurred" is logged
}

or,

  • Instantiate a dummy object in order to call the method, if the method inside the function is a method of an interface or struct, as discussed in this post.
lennon310
  • 3,132
  • 6
  • 16
  • 33
  • "Mocks increase coupling" I'm going to challenge that by saying mocks in and of themselves don't increase coupling. Unless you are purely writing mocks for the sake of it, needing a mock for your test is indicative that the implementation you are working towards has high coupling. – WhyAyala Nov 09 '22 at 16:41