How to mock HTTP requests in unit test with GoLang

Jhon Baron
7 min readFeb 12, 2023

--

Unit testing is a software testing technique in which individual units or components of the software are tested to verify that each unit works as expected. Unit testing aims to validate that each unit of the software application is working as intended. It helps in finding bugs early in the development process, making it easier and cheaper to fix them.

Mocking HTTP requests refers to the creation of fake HTTP requests for the purpose of testing. This is often used in unit tests to isolate the code under test from external dependencies like APIs, databases, or other services. By mocking these requests, the tests can focus on testing the code under test without having to worry about the behavior of these external dependencies.

Unit test workflow

Pros of Unit Testing:

  1. Early detection of bugs: Unit tests help in finding bugs early in the development process before they become more difficult and expensive to fix. This can save time and effort in the long run, as bugs caught early are easier and cheaper to fix.
  2. Increased confidence in code changes: Unit tests provide confidence in making changes to the code without breaking anything. When changes are made to the code, unit tests can be run to ensure that the changes have not broken any existing functionality. This can save time and effort that would otherwise be spent fixing bugs caused by code changes.
  3. Improved design: Unit testing forces developers to write modular, testable code, leading to better code design. When writing unit tests, developers must consider how their code can be easily tested and modularized, leading to better overall code design.
  4. Faster bug fixing: Unit tests make it easier and cheaper to fix bugs because they are caught early in the development process. Unit tests can quickly identify which parts of the code are causing problems, making it easier to locate and fix the bugs.
  5. Better documentation: Unit tests can serve as a form of documentation for the code, showing how it is intended to be used and what it should do. This can be especially helpful for new developers who are unfamiliar with the codebase, as unit tests can provide a clear and concise understanding of how the code works.
  6. Improved code quality: Unit tests can help improve the overall quality of the code by forcing developers to write more robust, reliable, and maintainable code. In the long run, this can lead to a better user experience and reduced maintenance costs.
  7. Automated testing: Unit tests can be automated, making it easy to run them regularly and quickly identify any problems in the code. Automated testing can save time and effort compared to manual testing and reduce the risk of human error.
Gopher testing code

Cons of Unit Testing:

  1. Time-consuming: This is especially true for large and complex codebases where there may be many units to test. It requires dedicated time and effort from the development team, and this time could be spent on other tasks such as adding new features or fixing bugs.
  2. Complexity: This is because unit tests themselves are code, and they can sometimes be difficult to read and understand, especially for someone who is unfamiliar with the codebase.
  3. Overhead: This can include additional time spent writing and maintaining tests, as well as increased memory usage and slower test execution times.
  4. False Positives and Negatives: Unit tests can sometimes produce false positives, where the tests pass even though there is a bug in the code. False negatives can also occur, where the tests fail even though the code is working correctly. These false results can be misleading and make it difficult to determine whether the code is working as expected.
  5. Maintenance: Unit tests must be updated whenever the code is updated. If the code changes, the unit tests must be updated to reflect these changes, which can be time-consuming and prone to errors.
  6. Limited scope: Unit tests only test individual units of code, not the overall system. This means that while unit tests can help ensure that individual units are working correctly, they do not guarantee that the overall system will work correctly.

Unit Testing in Golang

Golang’s built-in support for unit testing is one of its standout features, making it a popular choice for developers who want to write tests for their code. The testing package in Golang provides a comprehensive set of tools for writing and running tests, making it a powerful and flexible option for developers. With the testing package, developers can write tests for their code with a simple and intuitive syntax that makes it easy to get started with unit testing in Golang.

In addition to its simple syntax, the testing package also provides useful features like test coverage analysis. This feature allows developers to see which parts of their code have been covered by tests and which parts have not, making it easier to identify areas of the code that need more tests. The testing package also provides benchmarks, which allow developers to measure the performance of their code and compare it to other implementations. This can be especially useful when optimizing code for performance. Before starting, install the required libraries:

go get -u github.com/stretchr/testify/assert
go get -u github.com/jarcoal/httpmock

Copy and paste this piece of code into your code editor/IDE in a main_test.go file:

package main

import (
"io/ioutil"
"net/http"
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/jarcoal/httpmock"
)

func TestMain(m *testing.M) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
os.Exit(m.Run())
}

func TestMockHTTPRequest(t *testing.T) {
httpmock.RegisterResponder("GET", "https://api.example.com/users",
httpmock.NewStringResponder(200, `{"user_id":1, "username":"testuser"}`))

res, err := http.Get("https://api.example.com/users")
if err != nil {
t.Error(err)
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Error(err)
}
assert.Equal(t, 200, res.StatusCode)
assert.Equal(t, `{"user_id":1, "username":"testuser"}`, string(body))
}

Code explanation

  1. Import required packages: In the first line, you import the necessary packages such as testing, github.com/stretchr/testify/assert, and github.com/jarcoal/httpmock. The testing package provides the t *testing.T argument that is required for all Go test functions. The assert package is used to make assertions in tests, and the httpmock package provides the httpmock.Activate() and httpmock.DeactivateAndReset() functions that are used to activate and deactivate the mocking of HTTP requests, respectively.
  2. TestMain function: This function is used to set up and tear down the mock environment for all tests in the package. The httpmock.Activate() function is called to activate the mock environment, and the httpmock.DeactivateAndReset() function is called to reset the mock environment after all tests are completed.
  3. TestMockHTTPRequest function: This is the actual test function that makes an HTTP GET request to https://api.example.com/users and tests the response.
  4. Register a mock responder: The httpmock.RegisterResponder function is used to register a mock responder for the HTTP GET request to https://api.example.com/users. The httpmock.NewStringResponder function creates a new responder that returns a fixed string as the response body. In this case, the responder returns a JSON string {"user_id":1, "username":"testuser"} with a status code of 200.
  5. Make the GET request: The http.Get function is used to make the GET request to the mock endpoint https://api.example.com/users. If the request fails, an error is returned, and the test fails.
  6. Read the response body: The response body is read using the ioutil.ReadAll function, and the result is stored in the body variable. If there is an error reading the body, the test fails.
  7. Assert the response: Finally, the assert.Equal function is used to assert that the response status code is 200 and the response body is equal to the expected JSON string {"user_id":1, "username":"testuser"}. If either assertion fails, the test fails.

Output

Mocking unit test

In conclusion, mocking HTTP requests in unit tests with GoLang, Testify, and the httpmock library is a powerful and effective way to isolate and test specific units of code. These libraries provide an easy-to-use and flexible approach to mocking HTTP requests, making it easier to test the behavior of your code without relying on live external APIs. This leads to more reliable, repeatable, and deterministic tests that can help ensure the quality of your code. With the use of these libraries, developers can confidently make changes to their code, knowing that their tests will catch any unintended consequences.

Donation

Donations help me to continue providing valuable information and assistance to users like you. With your support, I can continue to improve and expand my knowledge base to better serve the community.

To donate, simply click on the PayPal link provided and select the amount you would like to contribute. PayPal is a safe and secure way to make a donation, and you can use it even if you don’t have an account. You can also scan this QR code for easy mobile PayPal donation:

Jhon Baron PayPal Donation QR

Your support is truly appreciated, and I thank you for considering a donation. Every little bit helps, and your generosity will help me to continue providing helpful and accurate information to users like you.

--

--