As we’ve been building out this API, we’ve covered authentication, logging, Dockerization, and more. But one thing we haven’t discussed yet is testing! If you want your API to be production-ready, adding solid unit tests is crucial. In this post, we’ll go over the basics of unit testing in Go, so you can catch bugs early and ship high-quality code.
Unit tests help you verify that each part of your codebase works as expected. They’re your first line of defense against bugs, regressions, and other nasty surprises. With Go’s built-in testing library, you can quickly set up tests that:
Ready to get started? Let’s dive in! ?
Go’s testing framework is simple and integrated right into the language. You can create a test file by naming it with the _test.go suffix. Let’s start by testing a simple function in main.go:
// main.go package main func Add(a, b int) int { return a b }
Now, create a file named main_test.go and add the following code:
// main_test.go package main import "testing" func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) } }
To run the test, just use:
go test
If everything works, you’ll see an ok message. ?
Now, let’s write a test for one of our HTTP handlers. We’ll use Go’s httptest package to create a mock HTTP request and response recorder.
// main_test.go package main import ( "net/http" "net/http/httptest" "testing" ) func TestGetBooksHandler(t *testing.T) { req, err := http.NewRequest("GET", "/books", nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(getBooks) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusOK { t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) } }
This way, you can isolate and test your handlers without having to spin up a full server. ?
Go has a built-in way to check test coverage. To see what percentage of your code is covered by tests, you can run:
go test -cover
For more detailed coverage, generate an HTML report:
go test -coverprofile=coverage.out go tool cover -html=coverage.out
Open the generated HTML file to visualize which parts of your code are covered. It’s a fantastic way to see where you may need additional testing.
When testing functions that depend on external services (e.g., database or external API calls), you can use interfaces to mock those dependencies.
// Define a simple interface for our database type Database interface { GetBooks() ([]Book, error) } // Implement a mock database type MockDatabase struct{} func (m MockDatabase) GetBooks() ([]Book, error) { return []Book{{Title: "Mock Book"}}, nil }
By using interfaces, you can replace the actual dependency with your mock during testing. This keeps your tests fast, isolated, and repeatable.
Now that you’ve started building unit tests, try adding tests to other parts of your API! ? Next week, we’ll look at integrating a CI/CD pipeline so these tests can run automatically with every change. Stay tuned!
Question for You: What’s your favorite testing tool or technique? Drop a comment below—I’d love to hear how other Go devs approach testing!
With these basics, you’re well on your way to writing solid tests that make your Go API more reliable. For more testing tips and advanced techniques, stay tuned for future posts. Happy testing! ?
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3