php editor Xiaoxin today brings you an introduction to Golang's simulation of forced change function definitions. Golang is an efficient and concise programming language with a powerful type system. However, in some cases, we may need to modify the definition of an existing function to meet specific needs. This article will introduce to you how to simulate the method of forcibly changing the function definition in Golang. Let's explore it together!
I have the following functions:
func getprice(date string) { url := (fmt.printf("http://endponint/%s", date)) resp, err := http.get(url) // unmarshall body and get price return price }
In order to unit test this function, I was forced to refactor to:
func getprice(client httpclient, date string) { url := (fmt.printf("http://endponint/%s", date)) resp, err := client.get(url) // unmarshall body and get price return price }
My test looks like this:
type MockClient struct { Response *http.Response Err error } func (m *MockClient) Get(url string) (*http.Response, error) { return m.Response, m.Err } mockResp := &http.Response{ StatusCode: http.StatusOK, Body: ioutil.NopCloser(strings.NewReader("mock response")), } client := &MockClient{ Response: mockResp, Err: nil, } data, err := getData(client, "http://example.com")
Is this the only way to test in go? Isn't there a way to mock the api that is not injected into the function?
The idiomatic way to use go for http testing is to use http/httptest (Example)
In your case, all you need to do is make the base url injectable:
var apiendpoint = "http://endpoint/" func getprice(date string) (int, error) { url := (fmt.printf("%s/%s", apiendpoint, date)) resp, err := http.get(url) // unmarshall body and get price return price, nil }
Then in each test:
srv := httptest.newserver(http.handlerfunc(func(w http.responsewriter, r *http.request) { // write the expected response to the writer })) defer srv.close() apiendpoint = srv.url price, err := getprice("1/1/2023") // handle error, check return
A better design is to wrap your api in a client struct
and make getprice
a receiver method:
type priceclient struct { endpoint string } func (pc *priceclient) getprice(date string) (int, error) { url := (fmt.printf("%s/%s", pc.endpoint, date)) resp, err := http.get(url) // unmarshall body and get price return price, nil }
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Write the expected response to the writer })) defer srv.Close() c := &PriceClient{Endpoint: srv.URL} price, err := c.GetPrice("1/1/2023") // Handle error, check return
For future reference, you should also take a look at gomock, as most other mocking problems you will encounter have no built-in solutions to the language.
The above is the detailed content of Golang simulation forces changes to function definitions. For more information, please follow other related articles on the PHP Chinese website!