8

For sentence

resp, err := client.Get(fmt.Sprintf("https://www.xxxxx/day?time=%s", time)) 

If I want to mock a response to this client.Get() in unit test, I should use httptest.server, but how can I bind the url (https://www.xxxxx/day?time=%s) to the url of httptest.server? so that when I call client.Get() it can return the response I set before. For some reason I cannot mock a client here.

1
  • 1
    It would be helpful to post your code so we can see what you're trying to accomplish. Commented Oct 26, 2017 at 6:51

3 Answers 3

6

Like this

func NewTestServerWithURL(URL string, handler http.Handler) (*httptest.Server, error) { ts := httptest.NewUnstartedServer(handler) if URL != "" { l, err := net.Listen("tcp", URL) if err != nil { return nil, err } ts.Listener.Close() ts.Listener = l } ts.Start() return ts, nil } 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot! This just saved my day - I couldn't figure out how to create a test server on a custom port and yours is the answer!
5

You don't, usually. You take the base URL from the server and give it to the client:

package main import ( "fmt" "net/http" "net/http/httptest" "testing" "time" ) func TestClient(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Verify request, send mock response, etc. })) defer server.Close() var client *http.Client var time time.Time baseURL := server.URL // Something like "http://127.0.0.1:53791" resp, err := client.Get(fmt.Sprintf(baseURL+"/day?time=%s", time)) if err != nil { t.Fatal(err) } // Verify response body if applicable resp.Body.Close() } 

Comments

0

The http.Client is a struct not an interface which makes mocking it difficult as you have seen. An alternative way of mocking it is passing in the external dependencies that a routine needs, so instead of directly using client.Get, you use clientGet - which is a function pointer that was handed into the routine.

From the unit test you can then create :

mockClientGet(c *http.client, url string) (resp *http.Response, err error) { // add the test code to return what you want it to. } 

Then in your main code use:

resp, err := clientGet(client, fmt.Sprintf("https://www.xxxxx/day?time=%s", time)) 

When calling the procedure normally, use the function pointer to http.Client.Get, and for your test pass in a pointer to your mock. It's not ideal, but I've not seen a nicer way around mocking non-interface external calls - and given its an external dependency, injecting it from the outside is not a bad thing.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.