Golang gotchas #4 testing http server and requests

devops terminal
3 min readSep 24, 2022
Photo by JJ Ying on Unsplash

Cases is we are going to develop an HTTP REST api server and fortunately Golang has provided such support through the net/http package. Writing the server is typically straightforward… however the challenging part is how to test it. In this blog, we would look into ways to run unit tests on our HTTP server.

How to code the server??

Before we run unit tests, how do we code the server at the first place? As mentioned Golang provides built-in support through the net/http package. The following is a code snippet on how to create a ServeMux (i.e. our server):

An instance of ServeMux is created, you can think of this is the HTTP server’s engine. We will add back the API endpoints and their corresponding handlers through the HandleFunc(). In our example, we added 2 endpoints named “/help” and “/stats”, each returning a static json response.

The 2nd last line of code is related to unit test and we will cover that right away…

Unit testing on a ServeMux

In general, there is no secret or much hardwork to unit test the HTTP server as Golang again provides support through net/http/httptest package.

From the previous code snippet, a testing server instance is created and started through calling the NewServer(serveMux_instance) api. Yep, that’s 1 big step and now we have a testing HTTP server running.

Next step is to create HTTP requests and send them to the testing server. Again there are many ways to create an HTTP request, for simplicity, we would be using the helper function Get() provided by net/http package. We can retrieve and verify the static json contents afterwards, the following code snippet provides an example on how to connect, retrieve and verify:

The tricky part is the target URL for access, we could hardcode the URL for sure, however it is recommended to retrieve this information through calling the testing server instance’s URL variable.

The rest of the code is simple and clear, we first extract everything from the httpResponse’s body, convert the []byte data to a string; finally verify if certain keywords exist in the converted string and that’s it~

Other thoughts…

The above approach is quick and dirty, however for unit test, we typically want to test the minimal “unit” instead of attached with other components such as an HTTP server. Hence another cleaner approach is we extract the HTTP handler’s logic out to a controller object instead.

Don’t be intimidated by the buzz word “controller”, it is merely just a simple struct containing all handler logics and most importantly, all handler functions would be employing standard / basic data types like string, int, float, bool ONLY. Which means no more framework specific data types like httpRequest and httpResponse.

The wins for such approach is unit testing is much cleaner and easier, there is no more concerns on setting up a proxy / test server to host the handler logics, we simply test the controller directly.

Also we might not be so lucky everytime, what if we are developing a TCP server this time? Golang does not provide any unit test support packages on TCP servers… Hence using the controller approach would be one of the workarounds.

gotcha (summary)~

In summary, we need to pay attention to 4 things:

  • to create a testing instance, we need to call net/http/httptest.NewServer() api and provide a ServeMux instance as the parameter
  • though the testing server would be started by itself and able to handle all HTTP request thereafter, we still need to call the Close() api to release resources once the server is done with the test
  • when we create the HTTP requests, remember to retrieve the server URL through the “URL” variable
  • finally revise the concept of controllers and make our code more modular as well as easier for unit testing

closings

Congrats~ We again equip a new technique and knowledge on Golang~ This time we know how to test an HTTP server. If you have any new ideas on how to do the same, do leave a comment and let me update this blog ASAP.

:) happy http communicating~

--

--

devops terminal

a java / golang / flutter developer, a big data scientist, a father :)