Add a test
Now that you've gotten your code to a stable place (nicely done, by the way), add a test. Testing your code during development can expose bugs that find their way in as you make changes. In this topic, you add a test for the Hello function.
Note: This topic is part of a multi-part tutorial that begins with Create a Go module.
Go's built-in support for unit testing makes it easier to test as you go. Specifically, using naming conventions, Go's testing package, and the go test command, you can quickly write and execute tests.
Steps
- Create a test file in the
greetingsdirectory calledgreetings_test.go.
Ending a file's name with
_test.gotells thego testcommand that this file contains test functions.
- Paste the following code into
greetings_test.goand save the file:
package greetings
import (
"testing"
"regexp"
)
// TestHelloName calls greetings.Hello with a name, checking
// for a valid return value.
func TestHelloName(t *testing.T) {
name := "Gladys"
want := regexp.MustCompile(`\b`+name+`\b`)
msg, err := Hello("Gladys")
if !want.MatchString(msg) || err != nil {
t.Errorf(`Hello("Gladys") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
// TestHelloEmpty calls greetings.Hello with an empty string,
// checking for an error.
func TestHelloEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Errorf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}In this code, you:
- Implement test functions in the same package as the code you're testing.
- Create two test functions to test the
greetings.Hellofunction. Test function names have the formTestName, where Name says something about the specific test. Also, test functions take a pointer to thetestingpackage'stesting.Ttype as a parameter. You use this parameter's methods for reporting and logging from your test. - Implement two tests:
TestHelloName: Calls theHellofunction with anamevalue and checks for a valid response message. If the call returns an error or an unexpected response message (one that doesn't include the name you passed in), it uses thetparameter'sErrorfmethod to print a message to the console.TestHelloEmpty: Calls theHellofunction with an empty string to confirm error handling. If the call returns a non-empty string or no error, it uses thetparameter'sErrorfmethod to print a message to the console.
- Run the test from the command line in the
greetingsdirectory using thego testcommand:
The
go testcommand executes test functions (whose names begin withTest) in test files (whose names end with_test.go). You can add the-vflag to get verbose output that lists all of the tests and their results.
The tests should pass:
$ go test
PASS
ok example.com/greetings 0.364s
$ go test -v
=== RUN TestHelloName
--- PASS: TestHelloName (0.00s)
=== RUN TestHelloEmpty
--- PASS: TestHelloEmpty (0.00s)
PASS
ok example.com/greetings 0.372s- Break the
Hellofunction to see a failing test:
The
TestHelloNametest checks the return value for the name you specified. To view a failing test result, modify theHellofunction to exclude the name from the response.
In greetings/greetings.go, replace the Hello function with the following code (note the highlighted changes):
// Hello returns a greeting for the named person.
func Hello(name string) (string, error) {
// If no name was given, return an error with a message.
if name == "" {
return name, errors.New("empty name")
}
// Create a message using a random format.
// message := fmt.Sprintf(randomFormat(), name)
message := fmt.Sprint(randomFormat())
return message, nil
}- Run the test again in the
greetingsdirectory:
This time, run
go testwithout the-vflag. The output will show results only for failed tests, which is useful when you have many tests. TheTestHelloNametest should fail, whileTestHelloEmptystill passes.
$ go test
--- FAIL: TestHelloName (0.00s)
greetings_test.go:15: Hello("Gladys") = "Hail, %v! Well met!", <nil>, want match for `\bGladys\b`, nil
FAIL
exit status 1
FAIL example.com/greetings 0.182sSummary
You've now written and executed tests for your Go code, learning how to use Go's built-in testing framework to ensure your functions behave as expected. This practice helps maintain code quality and catch bugs early in development.
In the next (and last) topic, you'll see how to compile and install your code to run it locally.