Skip to content

Instantly share code, notes, and snippets.

@maratori
Last active December 31, 2024 20:51
Show Gist options
  • Save maratori/8772fe158ff705ca543a0620863977c2 to your computer and use it in GitHub Desktop.
Save maratori/8772fe158ff705ca543a0620863977c2 to your computer and use it in GitHub Desktop.
Comparison of golang mocking libraries

Comparison of golang mocking libraries

Updated 2024-09-01

gomock testify + mockery mockio minimock moq

Library

GitHub stars s1 s2 + s3 s4 s5 s6
Latest release date d1 d2 + d3 d4 d5 d6
Maintained
Notes 1 2

Mock creation

Code generation 3 ✖️
Works without code generation 4
Use t.Cleanup() 5
Support generics

DSL

Execute custom func 6
Calls order 7
Wait for time.Duration 8
Wait for message from chan 9
Panic 10
Assert expectations with timeout
Return zero values by default 11
Capturer 12

Calls count

Exact calls count 13
Min/max calls count 14
Called at least once
Don't check calls count
Expect once by default 15

Matchers

Any value
Equal to (reflect)
Not equal to
Exact (==)
One of values
Regex
Substring
Is nil
Not nil
Type is
Length is ✔️ 16
Slice elements in any order
Slice contains
Map contains keys
Functional options
Logical operations on matchers
Custom matcher

Examples

gomock

func TestUberGomock(t *testing.T) {
	ctrl := gomock.NewController(t)
	m := NewMockMyInterface(ctrl)
	gomock.InOrder(
		m.EXPECT().Method(gomock.Any(), "abc").Return(123, nil),
		m.EXPECT().AnotherMethod(gomock.Any(), gomock.Len(3)),
	)
	...
}

testify/mock + mockery

func TestTestifyMock(t *testing.T) {
	m := mocks.NewMyInterface(t)
	m.EXPECT().Method(mock.Anything, "abc").After(5*time.Second).Return(123, nil).Once()
	m.EXPECT().AnotherMethod(mock.Anything, "abc").Return(0, nil).Once()
	...
}

mockio

func TestMockio(t *testing.T) {
	mock.SetUp(t, mockopts.StrictVerify())
	m := mock.Mock[MyInterface]()
	mock.WhenDouble(m.Method(mock.AnyContext(), mock.Equal("abc"))).ThenReturn(123, nil).Verify(mock.Once())
	mock.WhenDouble(m.AnotherMethod(mock.AnyContext(), mock.Regex("ab?c"))).Verify(mock.Once())
	captor := mock.Captor[string]()
	mock.WhenDouble(m.Method(mock.AnyContext(), captor.Capture()))
	...
	assert.Equal(t, "abc", captor.Last())
}

minimock

func TestMinimock(t *testing.T) {
	ctrl := minimock.NewController(t)
	m := NewMyInterfaceMock(ctrl)
	m.MethodMock.When(minimock.AnyContext, "abc").Then(123, nil)
	m.AnotherMethodMock.When(minimock.AnyContext, "abc").Then(0, nil)
	...
}

moq

func TestMoq(t *testing.T) {
	m := MyInterfaceMock{
		MethodFunc: func(ctx context.Context, s string) (int, error) {
			assert.Equal(t, "abc", s)
			return 123, nil
		},
		AnotherMethodFunc: func(ctx context.Context, s string) (int, error) {
			assert.Len(t, s, 1)
			return 0, nil
		},
	}
	t.Cleanup(func() {
		assert.Len(t, m.MethodCalls(), 1)
		assert.Len(t, m.AnotherMethodCalls(), 1)
	})
	...
}

Footnotes

  1. Google stopped maintaining the original gomock with 9K stars, Uber forked it and continue development

  2. mockio supports only amd64 and arm64 processors and it heavily depends on compiler internals and unsafe package

  3. CLI tool to auto generate mocks from interfaces

  4. Create mocks in runtime, without code generation

  5. Mock constructor uses t.Cleanup() to assert expectations after test by default

  6. Use arbitrary function to execute, allowing to implement any feature in the table

  7. Define expected order of calls

  8. Block execution of method using time.Sleep()

  9. Block execution of method using <- channel

  10. Panic instead of method execution

  11. Not defining return values leads to returning zero values

  12. Ability to capture actual call arguments to validate them later (not in mock)

  13. Define expected exact number of calls in test

  14. Define expected min/max number of calls in test

  15. Not defining number of calls leads to expectation that method to be called once

  16. There are only length matchers for slices and maps, not for strings

@maratori
Copy link
Author

@m1khal3v @Zurvarian I've added mockio to the table

@mbalabin
Copy link

Hi, thanks for your great comparison.

Just a small correction: minimock has a "Capturer" capability. All call parameters are stored in a mock and may be accessed later via Calls() function.

@maratori
Copy link
Author

maratori commented Sep 1, 2024

@mbalabin good catch, thanks! Actually, all libs but gomock allow introspecting calls afterward. IMO, mockio provides the best API for that, but I've updated the table accordingly.

@ovechkin-dm
Copy link

ovechkin-dm commented Sep 1, 2024

@m1khal3v @Zurvarian I've added mockio to the table

Thank you for adding mockio to your table.
The feature set for it is very accurate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment