
Go 的 mock 库提供了一个简单的方式来创建 mock 对象,例如 github.com/stretchr/testify/mock。这个库提供了一个 Mock 类型,可以用来创建 mock 对象。
Go 的测试 mock 可以使用 go test -v -cover -run=TestMock 来测试 mock 对象。这个命令可以帮助我们测试 mock 对象的行为。
Explore further: Golang vs Go
Mocking Basics
To create a mock object in Go, you can use the `On` method, which starts a description of an expectation of a specified method being called.
The `NewController` function from the `github.com/golang/mock/gomock` package is used to create a new controller to manage mocks in the test. This controller is then used to create mocks for external services, such as the `birthdaysRepoMock` and `phonebookMock` services.
To specify what method we expect to be called, we use the `EXPECT` function, which indicates that we expect some method to be called. The `GetUserIDByPhone` method is an example of a method that we might expect to be called.
Here's a summary of the key steps in creating a mock object:
Overview
Mocking is a powerful tool for testing our code, and it's based on a package called mock. This package allows us to mock our objects and verify that calls are happening as expected.
Curious to learn more? Check out: Install Golang Package
To use the mock package, we can create a new controller using gomock.NewController from the github.com/golang/mock/gomock package. This will help us manage mocks in our test.
The mock package provides a system that enables us to check if our code is calling functions as expected. We can verify this by specifying what method we expect to be called, what argument we expect to be passed, and what values we expect the method to return.
Here are some key points to keep in mind when working with the mock package:
- Use gomock.NewController to manage mocks in our test.
- Specify what method we expect to be called using EXPECT().
- Use gomock.Any() to indicate that any value is passed in.
- Specify what values we expect the method to return.
- Use Times() to specify how many times we expect the method to be called.
代码改写
In the realm of mocking, there's a clever technique called "代码改写" or code rewriting. This involves rewriting the original function to make it mockable. One popular tool for achieving this is go-mock, which was inspired by the go tool cover.
Go-mock works by inserting a trap function into the original code, which allows it to call the corresponding mock function. This is done at compile-time, making it a powerful tool for mocking.
On a similar theme: Golang Go
Here's an example of how it works:
Let's say we have a function `Add()` that we want to mock:
```go
func Add(a, b int) int {
return a + b
}
```
With go-mock, we can rewrite the `Add()` function to include a trap function:
```go
func (m *MockAdd) Add(a, b int) int {
m.TrapFunc()
return a + b
}
```
This allows us to call the mock function when testing.
Go-mock has some advantages, including:
- It's a pure Go implementation, making it compatible with all platforms and Go versions.
- It doesn't have concurrency issues, as it uses context to pass mock states.
However, it also has some limitations:
- It can only mock functions that you've written yourself, not external libraries or standard functions.
- It requires the function to take a context parameter, which can be a limitation.
- It can slow down test speed due to the code scanning and generation process.
- It doesn't support mocking generic functions.
Overall, go-mock is a powerful tool for mocking, but it's not a silver bullet. It's essential to consider its limitations and choose the right approach for your specific use case.
Running Mockgen
Mockgen is a powerful tool for generating mock objects. It has three modes of operation: archive, source, and package.
Mockgen can be run from the command line, and it's a good idea to understand its different modes. The archive mode is used to generate mock objects for a specific package, the source mode is used to generate mock objects for a specific file, and the package mode is used to generate mock objects for a specific directory.
Here's a brief overview of each mode:
Understanding the different modes of mockgen can help you use it more effectively in your testing workflow.
Return
The Return function is a crucial part of mocking, and it's used to specify the return arguments for an expectation.
According to the documentation, the Return function simply specifies the return arguments for the expectation, as stated in Example 4.
This is a key detail to keep in mind when writing your mock code, as it will determine what values are returned when the expected method is called.
The Return function is typically used in conjunction with the On function, which starts a description of an expectation of the specified method being called, as mentioned in Example 2.
By specifying the return arguments, you can ensure that your mock object behaves as expected and returns the correct values.
A different take: Golang Function Type
Mocking Techniques
Mocking is a crucial aspect of writing tests in Go. To create a mock object, you need to call the `NewController` function from the `github.com/golang/mock/gomock` package.
To create a mock object, you can use the `NewMock` function from the local mock package. This function takes the type of the object you want to mock as an argument.
Worth a look: Golang Create
There are several mocking techniques available in Go. One of the most common is using the `gomock.Any()` function to indicate that any value can be passed to a method.
Here are some common use cases for mocking:
- Mocking external services
- Mocking downstream HTTP calls
- Monkey patching
Here's a list of common mocking techniques:
Monkey patching is a powerful technique that allows you to modify the behavior of a function at runtime. However, it has some limitations, such as not supporting concurrent execution of tests.
Gomock
Gomock is a mocking framework for the Go programming language. It integrates well with Go's built-in testing package.
Gomock originates from Google's golang/mock repo. Unfortunately, Google no longer maintains this project.
Gomock is heavily used within Uber, which is why they decided to fork and maintain it going forward.
Broaden your view: Google Fi 是 什么
Mocking Functions
Mocking functions is a crucial part of writing effective tests in Go. You can use mocks to replace external services and dependencies with simulated objects that mimic their behavior.
To generate mock objects, you can use the mockgen tool, which is installed by running a command in your terminal. The tool will create a file named service.go in the mock package, containing the mock objects for all declared interfaces.
To create a mock object, you can use the NewMock function from the local mock package, specifying the interface you want to mock. For example, you can create a mock for the birthdaysRepo interface using NewMockbirthdaysRepo.
In your test, you can use the EXPECT function to specify what method you expect to be called on the mock object, along with the arguments you expect to be passed. You can also use the Return function to specify the values that the mock method should return.
Here's an example of how to use EXPECT and Return to test a method that calls the GetUserIDByPhone method on a phonebookMock service:
- phonebookMock — is the mocked service
- EXPECT() — indicates that we expect some method to be called
- GetUserIDByPhone — specifies what method we expect to be called
- phone — is the argument we expect to be passed in
- Return(uint32(0), errors.New(“some error”)) — specifies the values that the mock method should return
- Times(1) — specifies how many times we expect the method to be called
By using mocks, you can isolate the code you're testing and ensure that it behaves as expected, without relying on external services or dependencies.
Mocking Assertions
Mocking assertions are a crucial part of writing robust tests in Go.
AssertCalled asserts that the method was called, but be aware that it can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
AssertExpectations asserts that everything specified with On and Return was in fact called as expected, and calls may have occurred in any order.
AssertNumberOfCalls asserts that the method was called expectedCalls times, providing a clear expectation for the number of calls.
Mock AssertExpectations
The Mock AssertExpectations method is a crucial part of verifying that your mock objects behave as expected.
AssertExpectations asserts that everything specified with On and Return was in fact called as expected. Calls may have occurred in any order.
This is particularly useful when you have multiple expectations that need to be met, and you want to ensure that they all occur as planned.
AssertExpectations panics if any of the expectations are not met, so it's essential to use it in conjunction with On and Return to set up your expectations correctly.
In fact, AssertExpectations relies on the On and Return methods to define the expectations that need to be met, so make sure you've used these methods to set up your expectations before calling AssertExpectations.
AssertNotCalled
AssertNotCalled is a useful assertion in mocking. It asserts that the method was not called. However, it can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
This can be a tricky situation to navigate, but it's essential to be aware of this potential issue. The example in the article shows that AssertNotCalled can have unexpected behavior with pointer types.
In general, AssertNotCalled is a reliable way to verify that a method was not called, but it requires careful consideration of the types involved.
Mocking Control
Mocking control is crucial in Go testing, and it's where things can get a bit tricky. The Called and MethodCalled functions are used to tell the mock object that a method has been called.
These functions take an array of arguments to return, and if Call.WaitFor is set, they'll block until the channel is closed or receives a message. This is useful for testing asynchronous code.
If a call is unexpected, these functions will panic, which is a good thing - it means your tests will fail if something goes wrong. This helps catch errors early on.
Archive Mode
Archive mode is a powerful tool for generating mock interfaces from a package archive file.
To enable archive mode, you'll need to use the -archive flag in your command.
An import path and a comma-separated list of symbols should be provided as a non-flag argument to the command.
This means you'll need to specify the path to the import and the symbols you want to mock in the same line, separated by commas.
For example, you can use the -archive flag with an import path and a list of symbols like this:
Discover more: Golang Mode
Once

Once is a crucial feature in mocking control that allows you to specify how many times a mock should return a value. This feature is particularly useful when you need to test a function that calls a mock multiple times.
The Once feature is implemented using the func(*Call) Once method, which indicates that the mock should only return the value once. This means that after the mock returns the value once, it will not return it again, even if the function calls it multiple times.
I've found that using Once can help simplify your tests by preventing unnecessary repeated calls to the mock. For example, if you're testing a function that calls a mock twice, you can use Once to ensure the mock only returns the value once.
Call Twice
The Call Twice feature is a powerful tool in mocking control. It indicates that the mock should only return the value twice.

To use Call Twice, you need to set it up properly. This means using the Times method, which indicates that the mock should only return the indicated number of times.
In practice, this means you can use Call Twice to ensure your code behaves as expected in certain scenarios. For example, if you're testing a function that calls a method twice, you can use Call Twice to verify that the method is called exactly twice.
Call Twice is a flexible tool that can be used in a variety of situations. It's especially useful when you need to test code that calls a method multiple times, but not always.
Worth a look: Golang Use Cases
Unset
Unset is a powerful tool in mocking control that allows you to remove mock handlers that don't match the call instance arguments.
Only supported on call instances with static input arguments, Unset is a feature that's particularly useful when you need to reset your mocks to a clean state.

For example, if you have a mock handler like "MyMethod(2, 2)", that's the only handler that would remain after using Unset.
Unset removes all mock handlers that satisfy the call instance arguments from being called, giving you fine-grained control over your mocks.
This feature is especially useful when you need to isolate the behavior of a specific method or function, and you want to make sure that only the intended mock handlers are triggered.
Mocking HTTP Calls
Mocking HTTP Calls is a crucial technique in writing reliable unit tests.
You can use the net/http/httptest package to create a self-contained test server that listens on your system's local loopback interface.
This allows you to exercise code that makes HTTP calls without actually connecting to external services.
The httptest.NewServer() function takes an http.Handler as an argument, which gives you flexibility in creating custom responses or routes for your test server.
By parameterizing the URL that your code under test will connect to, you can easily swap out the actual server for a test server during your test.
In a test table, you can create and close a test server with a mocked response for each test case, or you can create a single test server for all test cases with different routes or logic.
Check this out: Golang Create File
Mocking Tests
To create mock objects for dependencies in Go, you'll need to create a new controller using gomock.NewController from the github.com/golang/mock/gomock package. This controller will manage mocks in your test.
You can then create mocks for external services using methods like NewMockbirthdaysRepo and NewMockphonebook from your local mock package. Specify these mocks as dependencies when creating your service using NewService function.
To describe all possible situations in your test, use EXPECT() to indicate that you expect a specific method to be called. For example, you might expect the GetUserIDByPhone method of the phonebookMock service to be called with the argument "phone". If the passed argument differs from the specified one, an error will be raised.
You can also use gomock.Any() to indicate that any value is passed in. For instance, you might expect the GetUserIDByPhone method to return a uint32 value of 0 and an error, and be called once.
Here's a summary of the steps to create mock objects for dependencies in Go:
Interface Mocking
Interface mocking is a powerful technique in Go testing. You can use it to mock out a small set of methods defined in a large interface.
To mock out a large interface, you can use the embedding technique. This involves embedding the large interface inside a mock struct, which implicitly satisfies the interface contract. This approach is useful when you only need to mock a few methods of the interface.
Here's an example of how to use the embedding technique:
In this example, the MockDynamoDBAPI and MockReadCloser structs embed the respective interfaces, allowing you to mock out specific methods without having to implement the entire interface.
Alternatively, you can use the golang/mock tool to generate mock implementations for your interfaces. This can save you time and effort, especially when working with large interfaces.
However, keep in mind that interface mocking can be invasive, requiring you to modify your business code to accommodate the mocking process. This can make your code harder to maintain, especially when dealing with complex interfaces.
For another approach, see: Golang Source
In some cases, it's better to use dependency injection to pass in mock objects instead of modifying your business code. This approach can be more elegant and natural, especially when working with interfaces that are already abstracted.
But, as with any technique, there are trade-offs to consider. Interface mocking can be more difficult to implement, especially when working with large interfaces or complex mocking scenarios.
Mocking Details
Mocking is a powerful technique in Go testing that allows you to isolate dependencies and make your tests more reliable. You can use mocks to replace external services, databases, or even HTTP calls.
To create a mock object, you can use the `gomock.NewController` function to manage mocks in the test. This function is part of the `github.com/golang/mock/gomock` package.
You can also use the `NewMock` function to create mocks for specific services, such as `NewMockbirthdaysRepo` and `NewMockphonebook`. These mocks can be used as dependencies when creating your service.
For more insights, see: Golang Create Error
To specify what a mock object should expect and return, you can use the `EXPECT` function and describe the expected method calls. For example, you can expect a method to be called with a specific argument, such as `phone` in the `GetUserIDByPhone` method.
Here's a summary of the mocking functions:
IsMethodCallable Added Inv1.6.0
In version 1.6.0, a new method called IsMethodCallable was added to the Mock function. This method checks if a method can be called.
The IsMethodCallable method returns false if the method was called more than the specified Repeatability. This means you need to set the Repeatability limit carefully to avoid false negatives.
You can use IsMethodCallable to verify that a method is callable, which is especially useful when working with complex mocking scenarios.
Mock MethodAdded Inv1.2.0
The Mock MethodCalled function is a game-changer for our testing needs. It tells the mock object that a specific method has been called and gets an array of arguments to return.

This function panics if the call is unexpected, meaning it hasn't been preceded by the right .On .Return() calls. If you're using Call.WaitFor, it'll block until the channel is closed or receives a message.
In other words, this function is super helpful for ensuring our tests are reliable and self-contained. It allows us to test our code without actually making external network calls, which is a major plus.
By using Mock MethodCalled, we can write more robust and efficient tests that give us peace of mind. It's a powerful tool that's definitely worth getting familiar with.
New String in 1.7.1
In the 1.7.1 release, a new String method was added to the Mock type.
This method provides a %v format string for Mock, which is used implicitly by Arguments.Diff if a Mock is passed.
The String method exists because go's default %v formatting traverses the struct without acquiring the mutex, which is detected by go test -race.
This is a key consideration when using Mocks in testing, as it can help catch potential issues with concurrency.
For your interest: Golang String to Time
TestData
TestData is a special field in a mock object that holds any data useful for testing. This data is completely ignored by Testify, allowing you to do whatever you like with it.
You can store any type of data in TestData, from simple strings to complex objects. The possibilities are endless.
In Testify, TestData is a flexible field that can be used to store any information you need for testing. This makes it a valuable tool for writing robust and reliable tests.
TestData is not used by Testify, so you can use it to store data that's relevant to your tests without worrying about it interfering with the testing process.
Featured Images: pexels.com


