Golang is an open source statically typed programming language that is welcomed and loved by more and more developers. When writing test code, it is often necessary to process Mock data. In this article, we will delve into the usage of Mock in Golang and how to process Mock data in different scenarios.
1. Why is Mocking needed?
During the testing process, we often encounter codes that need to be tested that rely on third-party services (such as APIs, databases, message queues, etc.). This requires us to use Mocking technology to simulate the response results of these dependent services to ensure that the test code can run independently and quickly.
In addition, Mocking can also be used to test the boundary conditions of the code (such as abnormal situations, such as input data not meeting requirements, etc.) to enhance the robustness and reliability of the code.
2. Mocking tools in Golang
There are many Mocking tools to choose from in Golang, some of the more popular tools are:
3. Use testify for Mocking
Below we will use testify as a Mocking tool and use an example to demonstrate how to use Mocking technology to test code.
We assume that the following function relies on an external HTTP API to obtain data:
func getOrderDetail(orderID int) (OrderDetail, error){ resp, err := http.Get("https://api.example.com/order/"+strconv.Itoa(orderID)) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("getOrderDetail API returns error status code: %d", resp.StatusCode) } var orderDetail OrderDetail return orderDetail, json.NewDecoder(resp.Body).Decode(&orderDetail) }
In order to test this function, we will need to Mock the HTTP request. testify provides two methods, MockHTTPServer and RoundTripper, to implement mocking of HTTP requests.
First, let’s take a look at how to use MockHTTPServer:
func TestGetOrderDetail(t *testing.T) { // 创建一个mock server server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 按照需要返回数据 if r.URL.Path == "/order/123" { fmt.Fprintln(w, "{\"orderID\":123,\"createDate\":\"2021-01-01\"}") } else { http.Error(w, "not found", http.StatusNotFound) } })) defer server.Close() // 将http client的请求地址指向mock server oldClient := http.DefaultClient http.DefaultClient = server.Client() defer func() { http.DefaultClient = oldClient }() // 调用 getOrderDetail() 函数 orderDetail, err := getOrderDetail(123) // 对 getOrderDetail() 的返回结果进行断言 assert.Nil(t, err) assert.Equal(t, 123, orderDetail.OrderID) // 假设OrderDetail中包含了字段 OrderID // 按照需要进行其他断言 }
In this example, we use the httptest.NewServer() method to create a mock server, and then simulate it in its handlerFunc() Returns the response and status code of the HTTP request.
Next, we point http.DefaultClient to the mock server so that when getOrderDetail() is called during the test, it can send a request to the mock server.
Finally, we use testify’s assertion method to check the returned results to ensure the correctness of the function.
In addition to MockHTTPServer, testify also provides the RoundTripper method to mock HTTP requests. This method provides a more flexible and controllable way to simulate HTTP requests. Users can customize the implementation of RoundTripper to switch to the mock data source at any time to better control the testing process. Readers can refer to the testify official documentation to learn more about the use of this method.
4. Use mockery for Mocking
In addition to testify, we can also use mockery for Mocking. Mockery is based on the language's built-in mock library (http://golang.org/pkg/mock/) and provides a code generation tool that can generate a framework for reusable Mock code. Mockery supports generating interface and external dependency Mock codes. We will introduce the interface mode Mocking as an example below.
First, we need to install the mockery generation tool:
go get github.com/vektra/mockery/v2/.../
Next, we define an interface and add a method to it:
type OrderDetailFetcher interface { FetchOrderDetail(orderID int) (OrderDetail, error) }
Then, in the root directory of the project Next, execute the following command to generate Mock code:
mockery --name OrderDetailFetcher
This will automatically generate a file named "mock_orderdetailfetcher.go", which already contains the automatically generated Mock code. We can use this Mock code in any code to implement the Mock data of the interface and complete the testing task.
Finally, we give a specific example to demonstrate how to use mockery to generate Mocking code:
type OrderDetail struct { OrderID int CreateDate string } type OrderDetailFetcher interface { FetchOrderDetail(orderID int) (OrderDetail, error) } func GetOrderDetail(fetcher OrderDetailFetcher, orderID int) (OrderDetail, error) { orderDetail, err := fetcher.FetchOrderDetail(orderID) if err != nil { return OrderDetail{}, err } return orderDetail, nil }
In this example, we define an interface named "OrderDetailFetcher" and A GetOrderDetail() function is implemented, which requires using the FetchOrderDetail() method in the OrderDetailFetcher interface to obtain order details. We can use the mockery command to automatically generate the Mock code for the FetchOrderDetail() method:
mockery --name OrderDetailFetcher
This command will generate a file named "mock_orderdetailfetcher.go" in the current directory, which contains the automatically generated Mock code. . We only need to combine the Mock code with our test code to complete the functional testing task.
func TestGetOrderDetail(t *testing.T) { orderDetail := OrderDetail{OrderID: 123, CreateDate: "2021-01-01"} // 创建一个mock对象 mockOrderDetailFetcher := &mocks.OrderDetailFetcher{} // 设定mock对象的mock调用及对应的返回结果 mockOrderDetailFetcher.On("FetchOrderDetail", 123).Return(orderDetail, nil) // 调用GetOrderDetail()函数 result, err := GetOrderDetail(mockOrderDetailFetcher, 123) // 校验返回结果及错误码 assert.Nil(t, err) assert.Equal(t, orderDetail, result) }
In this example, we define a mockOrderDetailFetcher object and use the On() method in the Mock library to specify a specific calling rule and corresponding results for its FetchOrderDetail() method - in If the orderID is 123, the orderDetail object is returned. When getting the FetchOrderDetail(123) of mockOrderDetailFetcher, the test code will directly return the preconfigured orderDetail object. Finally, we use testify's assertion method to verify the results.
Summarize
In this article, we introduce the relevant knowledge of Mocking in Golang and common Mocking tools, as well as how to use testify and mockery tools to perform Mocking operations and complete Mock testing of the target function. Through reasonable and correct application of Mocking technology, we can improve the readability, robustness, reliability and other aspects of the code. At the same time, Mocking can also help us quickly locate and solve possible problems in various codes, and improve the coverage and accuracy of the test code.
The above is the detailed content of Discuss the usage of Mock in Golang. For more information, please follow other related articles on the PHP Chinese website!