Mocking HTTP Requests in Go Without Modifying the Function

Listen to this Post

In the world of Go programming, testing functions that make HTTP requests can be tricky, especially when the function creates its own `http.Client{}` instance, bypassing http.DefaultClient. This article explores a solution to mock HTTP requests globally without modifying the function under test.

The Problem

  1. The function constructs a new `http.Client{}` every time.
  2. Calls were still going to the real API, even when using global mocks.
  3. No dependency injection was allowed, so modifying the function was not an option.

The Solution

The solution lies in overriding `http.DefaultTransport` with a custom transport. This approach ensures that all `http.Client{}` calls are intercepted globally, even inside functions that create their own client instances.

Why This Works

  • Overrides all `http.Client{}` calls globally.
  • Ensures no real API calls hit production.
  • No changes are required in the function under test.

You Should Know:

Here’s how you can implement this solution in your Go tests:

[go]
package main

import (
“net/http”
“net/http/httptest”
“testing”
)

// Custom RoundTripper to mock responses
type mockTransport struct {
roundTripFunc func(req http.Request) (http.Response, error)
}

func (m mockTransport) RoundTrip(req *http.Request) (http.Response, error) {
return m.roundTripFunc(req)
}

func TestFunctionWithHTTPRequest(t *testing.T) {
// Create a mock server
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte({"message": "success"}))
}))
defer server.Close()

// Override the DefaultTransport
http.DefaultTransport = &mockTransport{
roundTripFunc: func(req http.Request) (http.Response, error) {
// Redirect all requests to the mock server
req.URL.Host = server.URL[len(“http://”):]
req.URL.Scheme = “http”
return http.DefaultTransport.RoundTrip(req)
},
}

// Call the function under test
// functionUnderTest()
}
[/go]

Key Takeaway

If you’re testing functions that create their own http.Client{}, overriding `http.DefaultTransport` is a great trick to intercept requests without modifying existing code.

What Undercode Say

Mocking HTTP requests in Go can be challenging, especially when dealing with functions that create their own client instances. By overriding http.DefaultTransport, you can globally intercept HTTP requests, ensuring that your tests do not hit real APIs. This approach is particularly useful when you cannot modify the function under test.

Here are some additional commands and steps related to Go and HTTP testing:

1. Run Go Tests:

go test -v

2. Create a Mock HTTP Server:

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(<code>{"message": "success"}</code>))
}))
defer server.Close()

3. Override Default Transport:

http.DefaultTransport = &mockTransport{
roundTripFunc: func(req <em>http.Request) (</em>http.Response, error) {
req.URL.Host = server.URL[len("http://"):]
req.URL.Scheme = "http"
return http.DefaultTransport.RoundTrip(req)
},
}

4. Check HTTP Response:

resp, err := http.Get("http://example.com")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))

Expected Output:

By following the steps and using the provided code, you should be able to mock HTTP requests in Go without modifying the function under test. This ensures that your tests are reliable and do not depend on external APIs.

URLs:

References:

Reported By: Golang Bala – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅

Join Our Cyber World:

💬 Whatsapp | 💬 TelegramFeatured Image