$ go test
ok pkg/pets 1.303s
ok pkg/store 0.037s
ok pkg/store/storeadapter 0.025s
ok pkg/store/payment 0.111s
files ending with _test.go
functions starting with Test[A-Z]
func(t *testing.T)
signature
package pets
import "testing"
func TestDogBarks(t *testing.T) {
dog := NewAnimal(Dog)
if dog.Barks() == false {
// a dog should bark
}
}
t.Log()
t.Error()
t.Fatal()
t.Skip()
Tests are executed concurrently by default. Packages are tested in parallel by default.
import "testing"
func TestSomething(t *testing.T) {
t.Parallel()
}
# Run tests
$ go test
# Run tests for specific packages
$ go test ./pkg/...
# Run tests in verbose mode to see every output
$ go test -v
# Run a specific test
$ go test -run ^TestIntegration$
# Run tests with the race detector
$ go test -race
func TestDogBarks(t *testing.T) {
dog := NewAnimal(Dog)
if dog.Barks() == false {
t.Error("a dog should be able to bark")
}
}
func TestGetDog(t *testing.T) {
dog, err := getDog(1)
if err != nil { // oneliner?
t.Fatal(err)
}
if got, want := dog.ID, 1; got != want { // oneliner?
t.Errorf("id mismatch\nactual: %+v\nexpected: %+v", got, want)
}
}
func noError(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatal(err)
}
}
func TestGetDog(t *testing.T) {
dog, err := getDog(1)
noError(t, err)
// ...
}
Testify: https://github.com/stretchr/testify
import "github.com/stretchr/testify/assert"
import "github.com/stretchr/testify/require"
func TestGetDog(t *testing.T) {
dog, err := getDog(1)
require.NoError(t, err)
assert.Equal(t, 1, dog.ID)
}
type DogService struct {
Repository DogRepository
}
type Dog struct {
ID string
// ...
}
type DogRepository interface {
GetDog(id string) (Dog, err)
}
type inmemDogRepository struct{
dogs map[string]Dog
}
func (r inmemDogRepository) GetDog(id string) (Dog, error) {
dog, ok := r.dogs[id]
if !ok {
return Dog{}, ErrDogNotFound
}
return dog, nil
}
Testify: github.com/stretchr/testify/mock
func TestFoo(t *testing.T) {
foo := new(Foo)
foo.On("DoSomething", 123).Return(true, nil)
bar(foo)
foo.AssertExpectations(t)
}
Generator: https://github.com/vektra/mockery
type Stringer struct {
mock.Mock
}
func (m *Stringer) String() string {
ret := m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
package pets
import "testing"
func TestDogBarks(t *testing.T) {
dog := NewAnimal(Dog)
if dog.Barks() == false {
// a dog should bark
}
}
func TestDogBites(t *testing.T) {
// ...
}
package pets
import "testing"
func TestDog(t *testing.T) {
dog := NewAnimal(Dog)
t.Run("barks", func(t *testing.T) {
// ...
})
t.Run("bites", func(t *testing.T) {
// ...
})
}
$ go test -run TestDog/barks
Testify: github.com/stretchr/testify/suite
func TestDogTestSuite(t *testing.T) {
suite.Run(t, new(DogTestSuite))
}
type DogTestSuite struct {
suite.Suite
}
func (s *DogTestSuite) SetupTest() {}
func (s *DogTestSuite) AfterTest(suiteName, testName string) {}
func (s *DogTestSuite) Test_Barks() {
// ...
}
func TestSplit(t *testing.T) {
tests := struct{
name string
input string
sep string
want []string
} {
{
name: "empty",
input: "",
sep: ",",
want: []string{""},
},
}
}
func TestSplit(t *testing.T) {
// ...
for _, tc := range tests {
tc := tc
t.Run(tc.name, func(t *testing.T) {
assert.Equal(t, Split(tc.input, tc.sep), tc.want)
})
}
}
//go:build integration
package foo
func TestFoo(t *testing.T) {
// ...
}
$ go test -tags integration
https://peter.bourgon.org/blog/2021/04/02/dont-use-build-tags-for-integration-tests.html
package foo
func TestFoo(t *testing.T) {
if t.Short() {
t.Skip("skipping test in short mode")
}
// ...
}
$ go test -short
func TestFoo(t *testing.T) {
fooAddr := os.Getenv("FOO_ADDR")
if fooAddr == "" {
t.Skip("set FOO_ADDR to run this test")
}
f, err := foo.Connect(fooAddr)
// ...
}
$ FOO_ADDR=127.0.0.1:8080 go test
func TestIntegration(t *testing.T) {
if m := flag.Lookup("test.run").Value.String(); m == "" || !regexp.MustCompile(m).MatchString(t.Name()) {
t.Skip("skipping as execution was not requested explicitly using go test -run")
}
t.Run("foo", testFoo)
// ...
}
func testFoo(t *testing.T) {
// ...
}
$ go test -run ^TestIntegration$
Take them with a grain of salt.
$ go test -race
testing/fstest
MapFS
TB.Setenv
func TestFoo(t *testing.T) {
t.Setenv("KEY", "VALUE")
}
Must not be used in parallel tests (ie. with t.Parallel
).
func FuzzParseQuery(f *testing.F) {
f.Add("x=1&y=2")
f.Fuzz(func(t *testing.T, queryStr string) {
// ...
})
}
Questions?