Overview

When writing unit tests, mocking and stubbing can help you a lot. In this post, we’ll take a look at what mocking and stubbing are and how they differ from each other, and then go through some Golang example code to understand them in more detail.

What is Mocking

Mocking simulates the behavior of an object. It is used when the code under test interacts with external systems, methods, or other classes. Mock objects define expected behavior (e.g., method calls, return values) and are used to verify that the actual code meets those expectations. Mocking is primarily focused on behavior verification.

What is Stubbing

Stubbing is used to return a specific response from a method called by the code under test. The Stub object takes the place of other components that the code under test relies on, and provides a predefined response. Stubbing is primarily used for state verification, focusing on validating the state changes or return values that a test case expects.

Difference between Mocking and Stubbing

Mocking and stubbing are both techniques used in software testing, especially unit testing, to enable independent verification of the code under test by removing or simplifying external dependencies. While they may seem similar, there are important differences in their purpose and methods.

See: https://martinfowler.com/bliki/TestDouble.html

Mocking verification

<a href="https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da" target="_blank" rel="noopener">https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da</a>

https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da

Mock objects typically verify that a specific method call you set up in a test happens as expected. For example, you might want to check if a certain method is called with certain arguments, how many times it’s called, etc.

Stubbing verification method

<a href="https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da" target="_blank" rel="noopener">https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da</a>

https://blog.pragmatists.com/test-doubles-fakes-mocks-and-stubs-1a7491dfa3da

Stubbing provides only the result of the called method, and tests use this result to verify that certain logic works as expected. Stubbing does not validate the behavior of whether it was called, how many times it was called, etc.

Mocking and stubbing with Golang

Let’s take a look at a simple implementation of mocking and stubbing with Golang: write a mocking and stubbing implementation for an interface that fetches external data. In Golang, it’s easier to validate Mocking by using an external library that supports it rather than writing it yourself.

The Golang example will be implemented using mockery, and I’ll save the detailed usage of mockery for another post.

Define interface

1// DataService.go
2
3type DataService interface {
4    FetchData(param string) (string, error)
5}

Mocking Example

The example below uses the Mockery library to create a Mock object for the DataService interface, and uses it to simulate a call to the FetchData method.

In this test, we are verifying that FetchData is called correctly through the AssertExpectations function on the mock object.

Writing an Implementation

1mockery --name=DataService --dir=./mypackage --output=./mypackage/mocks --outpkg=mocks

testcode

 1// DataService_test.go
 2func TestFetchData(t *testing.T) {
 3// Create a Mock object
 4mockDataService := &mocks.DataService{}
 5
 6	// Set expectations
 7	expectedData := "mocked data"
 8	mockDataService.On("FetchData", mock.Anything).Return(expectedData, nil)
 9
10	// Call the function under test
11	result, err := mockDataService.FetchData("param")
12
13	// Validate
14	mockDataService.AssertExpectations(t)
15	if err != nil {
16		t.Fatalf("Expected no error, but got %s", err)
17	}
18	if result != expectedData {
19		t.Fatalf("Expected %s, but got %s", expectedData, result)
20	}
21}

Stubbing examples

When you use stubbing to express the same case, you write your own implementation of the interface and set it up to return the specific data you need for your tests. Stubs focus on simply returning the expected result, without any complex logic or actual interaction with external systems.

Whereas mocking focuses on validating against specific behaviors, in stubbing, a specific function is simply intended to return a value and check its state afterward.

High-level verification is not possible, but it has advantages over mocking. As you can see, stubbing is more reusable than mocking, and if you don’t need complex verification, stubbing can be a good choice.

Create an Implementation

1// stubs.go
2package mypackage
3
4type StubDataService struct{}
5
6func (s *StubDataService) FetchData(param string) (string, error) {
7    // Return stubbed data
8    return "stubbed data", nil
9}

TestCode

 1// DataService_test.go
 2func TestFetchDataWithStub(t *testing.T) {
 3	// Create a Stub object
 4	stubDataService := &StubDataService{}
 5
 6	// Call the function under test
 7	result, err := stubDataService.FetchData("param")
 8
 9	// Validate
10	if err != nil {
11		t.Fatalf("Expected no error, but got %s", err)
12	}
13	expectedData := "stubbed data"
14	if result != expectedData {
15		t.Fatalf("Expected %s, but got %s", expectedData, result)
16	}
17}

Summary

In this post, we explored the concepts of mocking and stubbing using Golang. Mocking is used to simulate the behavior of an object and validate the expected behavior, while stubbing is used to verify that certain logic works as expected by returning a specific response. When writing unit tests, I think you’ll be able to write more efficient tests if you don’t always consider Mocking, but instead consider different options depending on the situation.