Extremely flexible golang deep comparison, extends the go testing package.
Currently supports go 1.16 → 1.23.
- Latest news
- Synopsis
- Description
- Installation
- Functions
- Available operators
- Helpers
- See also
- License
- FAQ
- 2023/12/27: v1.14.0 release;
- 2023/03/18: v1.13.0 release;
- 2022/08/07: v1.12.0 release;
- see commits history for other/older changes.
Make golang tests easy, from simplest usage:
import (
"testing"
"github.com/maxatome/go-testdeep/td"
)
func TestMyFunc(t *testing.T) {
td.Cmp(t, MyFunc(), &Info{Name: "Alice", Age: 42})
}
To a bit more complex one, allowing flexible comparisons using TestDeep operators:
import (
"testing"
"github.com/maxatome/go-testdeep/td"
)
func TestMyFunc(t *testing.T) {
td.Cmp(t, MyFunc(), td.Struct(
&Info{Name: "Alice"},
td.StructFields{
"Age": td.Between(40, 45),
},
))
}
Or anchoring operators directly in literals, as in:
import (
"testing"
"github.com/maxatome/go-testdeep/td"
)
func TestMyFunc(tt *testing.T) {
t := td.NewT(tt)
t.Cmp(MyFunc(), &Info{
Name: "Alice",
Age: t.Anchor(td.Between(40, 45)).(int),
})
}
To most complex one, allowing to easily test HTTP API routes, using flexible operators:
import (
"testing"
"time"
"github.com/maxatome/go-testdeep/helpers/tdhttp"
"github.com/maxatome/go-testdeep/td"
)
type Person struct {
ID uint64 `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
CreatedAt time.Time `json:"created_at"`
}
func TestMyApi(t *testing.T) {
var id uint64
var createdAt time.Time
testAPI := tdhttp.NewTestAPI(t, myAPI) // ← ①
testAPI.PostJSON("/person", Person{Name: "Bob", Age: 42}). // ← ②
Name("Create a new Person").
CmpStatus(http.StatusCreated). // ← ③
CmpJSONBody(td.JSON(`
// Note that comments are allowed
{
"id": $id, // set by the API/DB
"name": "Alice",
"age": Between(40, 45), // ← ④
"created_at": "$createdAt", // set by the API/DB
}`,
td.Tag("id", td.Catch(&id, td.NotZero())), // ← ⑤
td.Tag("createdAt", td.All( // ← ⑥
td.HasSuffix("Z"), // ← ⑦
td.Smuggle(func(s string) (time.Time, error) { // ← ⑧
return time.Parse(time.RFC3339Nano, s)
}, td.Catch(&createdAt, td.Between(testAPI.SentAt(), time.Now()))), // ← ⑨
)),
))
if !testAPI.Failed() {
t.Logf("The new Person ID is %d and was created at %s", id, createdAt)
}
}
- the API handler ready to be tested;
- the POST request with automatic JSON marshalling;
- the expected response HTTP status should be
http.StatusCreated
and the line just below, the body should match theJSON
operator; - some operators can be embedded, like
Between
here; - for the
$id
placeholder,Catch
its value: put it inid
variable and check it isNotZero
; - for the
$createdAt
placeholder, use theAll
operator. It combines several operators like a AND; - check that
$createdAt
date ends with "Z" usingHasSuffix
. As we expect a RFC3339 date, we require it in UTC time zone; - convert
$createdAt
date into atime.Time
using a custom function thanks to theSmuggle
operator; - then
Catch
the resulting value: put it increatedAt
variable and check it is greater or equal thantestAPI.SentAt()
(the time just before the request is handled) and lesser or equal thantime.Now()
.
See tdhttp
helper or the
FAQ
for details about HTTP API testing.
Example of produced error in case of mismatch:
go-testdeep is historically a go rewrite and adaptation of wonderful Test::Deep perl.
In golang, comparing data structure is usually done using reflect.DeepEqual or using a package that uses this function behind the scene.
This function works very well, but it is not flexible. Both compared structures must match exactly and when a difference is returned, it is up to the caller to display it. Not easy when comparing big data structures.
The purpose of go-testdeep, via the
td
package
and its
helpers,
is to do its best to introduce this missing flexibility using
"operators", when the
expected value (or one of its component) cannot be matched exactly,
mixed with some useful
comparison functions.
See go-testdeep.zetta.rocks for details.
$ go get github.com/maxatome/go-testdeep
The goal of helpers is to make use of go-testdeep
even more powerful
by providing common features using
TestDeep operators
behind the scene.
The package github.com/maxatome/go-testdeep/helpers/tdhttp
provides
some functions to easily test HTTP handlers.
See tdhttp
documentation for details or
FAQ for an
example of use.
The package github.com/maxatome/go-testdeep/helpers/tdsuite
adds tests
suite feature to go-testdeep in a non-intrusive way, but easily and powerfully.
A tests suite is a set of tests run sequentially that share some data.
Some hooks can be set to be automatically called before the suite is run, before, after and/or between each test, and at the end of the suite.
See tdsuite
documentation for details.
The package github.com/maxatome/go-testdeep/helpers/tdutil
allows to
write unit tests for go-testdeep helpers and so provides some helpful
functions.
See
tdutil
for details.
- testify: a toolkit with common assertions and mocks that plays nicely with the standard library
- go-cmp: package for comparing Go values in tests
go-testdeep
is released under the BSD-style license found in the
LICENSE
file in the root directory of this source tree.
Internal function deepValueEqual
is based on deepValueEqual
from
reflect
golang package licensed
under the BSD-style license found in the LICENSE
file in the golang
repository.
Uses two files (bypass.go
& bypasssafe.go
) from
Go-spew which is licensed under
the copyfree ISC License.
Public Domain Gopher provided by Egon Elbre. The Go gopher was designed by Renee French.
See FAQ.