0
0
GoHow-ToBeginner · 3 min read

How to Mock in Go: Simple Guide with Examples

In Go, you mock by defining interfaces for the parts you want to replace and then creating mock implementations of those interfaces. Use these mocks in your tests to simulate behavior without calling real dependencies.
📐

Syntax

To mock in Go, first define an interface that describes the methods you want to mock. Then create a struct that implements this interface with mock behavior. Use this mock struct in your tests instead of the real implementation.

This pattern helps isolate the code under test from external dependencies.

go
type Service interface {
    DoSomething(input string) (string, error)
}

// Mock struct implementing Service
type MockService struct {
    MockDoSomething func(input string) (string, error)
}

func (m *MockService) DoSomething(input string) (string, error) {
    return m.MockDoSomething(input)
}
💻

Example

This example shows how to use a mock to test a function that depends on a Service interface. The mock returns a fixed response without calling real code.

go
package main

import (
    "errors"
    "fmt"
)

type Service interface {
    DoSomething(input string) (string, error)
}

type RealService struct{}

func (r *RealService) DoSomething(input string) (string, error) {
    return "Real: " + input, nil
}

type MockService struct {
    MockDoSomething func(input string) (string, error)
}

func (m *MockService) DoSomething(input string) (string, error) {
    return m.MockDoSomething(input)
}

func Process(s Service, input string) (string, error) {
    return s.DoSomething(input)
}

func main() {
    // Using real service
    real := &RealService{}
    result, _ := Process(real, "hello")
    fmt.Println(result)

    // Using mock service
    mock := &MockService{
        MockDoSomething: func(input string) (string, error) {
            if input == "fail" {
                return "", errors.New("mock error")
            }
            return "Mocked: " + input, nil
        },
    }
    res1, err1 := Process(mock, "test")
    fmt.Println(res1, err1)
    res2, err2 := Process(mock, "fail")
    fmt.Println(res2, err2)
}
Output
Real: hello Mocked: test <nil> <nil> mock error
⚠️

Common Pitfalls

  • Not using interfaces: Without interfaces, you cannot easily replace real implementations with mocks.
  • Mocking too much: Mock only external dependencies, not the code you want to test.
  • Complex mocks: Keep mocks simple and focused on the behavior needed for the test.
  • Ignoring errors: Always handle errors in mocks to test failure cases.
go
/* Wrong: Using concrete type directly, no interface */

// func Process(s *RealService, input string) (string, error) {
//     return s.DoSomething(input)
// }

/* Right: Use interface to allow mocking */

type Service interface {
    DoSomething(input string) (string, error)
}

func Process(s Service, input string) (string, error) {
    return s.DoSomething(input)
}
📊

Quick Reference

Remember these steps to mock in Go:

  • Define an interface for the dependency.
  • Create a mock struct implementing the interface.
  • Implement mock methods with custom behavior.
  • Use the mock in your tests to simulate different scenarios.

Key Takeaways

Always define interfaces to enable mocking in Go.
Create simple mock structs implementing those interfaces for tests.
Use mocks to simulate both success and error cases.
Avoid mocking your own code; mock only external dependencies.
Keep mocks focused and easy to maintain.