Testing an HTTP Server
A small example of testing an HTTP server endpoint
This is a small example of how to test an HTTP server endpoint. I’ve gotten in the bad habit of not writing tests for my Go code, and I need to brush up on how to write tests.
I’ll likely do a better version of this later that uses mocks, but for now, this will suffice.
The code below is split into 3 different files:
main.go
to run the applicationserver.go
that defines all of the server logicserver_test.go
that defines a test for the server’s sole endpoint
main.go
The contents of main.go
are:
package main
func main() {
:= NewServer()
s .Run()
s}
This file really just bundles everything together and runs the application
server.go
The contents of server.go
are:
package main
import (
"fmt"
"net/http"
)
//define a user type
type User struct {
string
FirstName int
Age }
//define a server type
type Server struct {
*http.Server
Srvr []*User
UserStore }
//create a new server with some dummy data included
func NewServer() *Server {
return &Server{
: &http.Server{
Srvr: ":8080",
Addr},
: []*User{
UserStore{
: "John",
FirstName: 29,
Age},
{
: "Kendall",
FirstName: 32,
Age},
},
}
}
//define a function to handle an endpoint requesting the user's age
func (s *Server) HandleGetUserAge(w http.ResponseWriter, r *http.Request) {
:= r.URL.Query()
q := q.Get("first_name")
firstName
for _, user := range s.UserStore {
if user.FirstName == firstName {
.WriteHeader(http.StatusOK)
w.Fprint(w, user.Age)
fmtreturn
}
}
.WriteHeader(http.StatusNotFound)
w.Fprint(w, "user not found")
fmt}
//run the server
func (s *Server) Run() {
.HandleFunc("/user", s.HandleGetUserAge)
http.Srvr.ListenAndServe()
s}
This is all fairly self explanatory.
server_test.go
The contents of server_test.go
, which is the thing I’m actually interested in here, are:
package main
//write a test for the handleGetUserAge endpoint
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestHandleGetUserAge(t *testing.T) {
, err := http.NewRequest("GET", "/user?first_name=John", nil) //create a request
reqif err != nil {
.Fatal(err)
t}
//note that creating a mock with a datastore is probably a better way to do this, but I defined the handler above as a method on the server, so I need another server here
:= NewServer() //create a new server
s
:= httptest.NewRecorder() //create a response recorder, which is a tool that lets us test http responses
rr := http.HandlerFunc(s.HandleGetUserAge) //create a handler function
handler
.ServeHTTP(rr, req) //call the handler function
handler//note that since rr is a pointer, its data can be updated when this handler is called
if status := rr.Code; status != http.StatusOK { //check the status code
.Errorf("handler returned wrong status code: got %v want %v",
t, http.StatusOK)
status}
:= "29" //expected response. We know this is what shoul be returned since this is John's age in the dummy data we created
expected := rr.Body.String() //get the response body
got if got != expected { //check the response body
.Errorf("handler returned unexpected body: got %v want %v",
t, expected)
got}
}
If we run the test, we’ll see that it passes.