Extremely flexible golang deep comparison, extends the go testing package and tests HTTP APIs

Overview

go-testdeep

Build Status Coverage Status Go Report Card GoDoc Version Mentioned in Awesome Go

go-testdeep

Extremely flexible golang deep comparison, extends the go testing package.

Latest news

Synopsis

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":       "Bob",
  "age":        42,
  "created_at": "$createdAt", // set by the API/DB
}`,
      td.Tag("id", td.Catch(&id, td.NotZero())),        // ← ④
      td.Tag("created_at", 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)
  }
}
  1. the API handler ready to be tested;
  2. the POST request with automatic JSON marshalling;
  3. the expected response HTTP status should be http.StatusCreated and the line just below, the body should match the JSON operator;
  4. for the $id placeholder, Catch its value: put it in id variable and check it is NotZero;
  5. for the $createdAt placeholder, use the All operator. It combines several operators like a AND;
  6. check that $createdAt date ends with "Z" using HasSuffix. As we expect a RFC3339 date, we require it in UTC time zone;
  7. convert $createdAt date into a time.Time using a custom function thanks to the Smuggle operator;
  8. then Catch the resulting value: put it in createdAt variable and check it is greater or equal than testAPI.SentAt() (the time just before the request is handled) and lesser or equal than time.Now().

See tdhttp helper or the FAQ for details about HTTP API testing.

Example of produced error in case of mismatch:

error output

Description

go-testdeep is 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.

Installation

$ go get -u github.com/maxatome/go-testdeep

Helpers

The goal of helpers is to make use of go-testdeep even more powerful by providing common features using TestDeep operators behind the scene.

tdhttp or HTTP API testing helper

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.

tdutil aka the helper of helpers

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.

See also

  • testify: a toolkit with common assertions and mocks that plays nicely with the standard library
  • go-cmp: package for comparing Go values in tests

License

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.

FAQ

See FAQ.

Comments
  • Ignore unexported struct fields?

    Ignore unexported struct fields?

    I want to compare all fields in two large structs, except the unexported fields. Is there any way to achieve that without manually specifying each field in a SStruct? I might be missing an operator/helper function, but the best solution that comes to my mind is to compare the JSON representation of the two structs.

    Example for clarification:

    type X struct {
      Field1      int
      Field2      int
      Field3      int
      Field4      int
      Field5      int
      fieldIgnore int // <--- want to ignore this when doing a t.Cmp(x1, x2)
    }
    
    opened by siadat 13
  • Comparison of reflect.Value types

    Comparison of reflect.Value types

    Here to annoy you again :P

    I'm aiming to support the encoding of reflect.Type and reflect.Value in my encoding library. go-testdeep has been amazing for tests, but test cases where I compare a reflect.Value values, go-testdeep compares them like a typical struct, and doesn't compare the underlying value inside reflect.Value.

    This means a reflect.Value of a value is only equal if the underlying value is at the same pointer address, and the reflect.Value was created in the same way due to how reflect uses the flag field in reflect.Value.

    In any case, I don't think the semantics of how reflect.Value works is important. For my use case, I'm looking to compare the value inside reflect.Value, and I don't care so much about the reflect.Value itself, e.g if both are addressable or if only one is, although an argument could be made for this. I believe something like

    if got.Type() == reflect.TypeOf(reflect.Value{}) {
        return deepValueEqual(ctx, got.Interface().(reflect.Value), expected.Interface().(reflect.Value))
    }
    

    in deepValueEqual could work, but I'm unsure how this might work with the rest of the codebase. I also know that the ptr field of reflect.Value could introduce an infinite recursion, an extreme case being a reflect.Value that is the value of itself, but less contrived examples do exist.

    I'd be happy to experiment implementing this and submit a PR. Is this something you'd want to support?

    opened by stewi1014 8
  • Recursive SubMap/SuperMap?

    Recursive SubMap/SuperMap?

    Is there a way to compare submaps/supermaps recursively (make sure that partial compare is propagated to nested maps)? Based on what I see, the default behavior is that only the parent map is compared partially, while all nested maps are expected to have exact match.

    question 
    opened by artem-nefedov 4
  • remove Run method from TF interface

    remove Run method from TF interface

    The TestingFT interface includes the Run method, which uses the *testing.T parameter directly, which means that go-testdeep cannot be used with *testing.B or alongside other testing helper packages such as quicktest.

    If you embed testing.TB inside T instead of defining your own testingFT interface, this problem goes away, and additionally you can take advantage of new features added to testing.TB (Cleanup for example) automatically and without breaking your API by adding methods to an interface type.

    opened by rogpeppe 4
  • feat(tdhttp): add CmpCookies

    feat(tdhttp): add CmpCookies

    [email protected]:~/git/go-testdeep$ go test ./... -cover
    ok      github.com/maxatome/go-testdeep 0.038s  coverage: [no statements]
    ok      github.com/maxatome/go-testdeep/helpers/nocolor 0.047s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdhttp  0.075s  coverage: 99.4% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdhttp/internal 0.017s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdsuite 0.019s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdutil  0.004s  coverage: 99.4% of statements
    ok      github.com/maxatome/go-testdeep/internal/anchors        0.022s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/color  0.011s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/ctxerr 0.007s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/dark   0.003s  coverage: 95.6% of statements
    ok      github.com/maxatome/go-testdeep/internal/flat   0.011s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/hooks  0.009s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/json   0.006s  coverage: 91.6% of statements
    ?       github.com/maxatome/go-testdeep/internal/location       [no test files]
    ?       github.com/maxatome/go-testdeep/internal/test   [no test files]
    ok      github.com/maxatome/go-testdeep/internal/trace  0.005s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/types  0.008s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/util   0.016s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/visited        0.007s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/td      0.209s  coverage: 99.8% of statements
    
    opened by Julien2313 3
  • Difficult to call t.Parallel with td.T

    Difficult to call t.Parallel with td.T

    testdeep encourages wrapping the *testing.T into a *td.T. This unfortunately makes it difficult to call t.Parallel() on the *testing.T once hidden behind the *td.T.

    func TestFoo(tt *testing.T) {
        t := td.NewT(tt)
        
        t.Run("foo", func(t *td.T) {
            // t.Parallel() <<< errors because Parallel() does not exist
            //                  on the testing.TB interface.
            
            t.Cmp(...)
        })
        
        t.Run("bar", func(t *td.T) {
            // t.Parallel()
            
            t.Cmp(...)
        })
    }
    

    It's possible to call t.Parallel() on the *testing.T with some upcasting on the wrapped testing.TB.

    func Parallel(t *td.T) {
    	tp, ok := t.TB.(interface{ Parallel() })
    	if ok {
    		tp.Parallel()
    	}
    }
    

    If you're open to addressing this within testdeep, there are two straightforward options:

    • Add a top-level func Parallel(*td.T) that does the same as above. Usage would then be,

      t.Run("foo", func(t *td.T) {
          td.Parallel(t)
      
          t.Cmp(...)
      })
      
    • Add a Parallel() method on td.T. Usage:

      t.Run("foo", func(t *td.T) {
          t.Parallel()
      
          t.Cmp(...)
      })
      

    The latter is closest to what people already do with *testing.T so it might be preferable.


    Separately, either choice opens room for a setting in testdeep to always call t.Parallel() for subtests invoked with a specific *td.T.Run. For example,

    func TestFoo(tt *testing.T) {
        t := td.NewT(tt).AlwaysParallel(true)
        
        t.Run("foo", func(t *td.T) {
            // already parallel
            t.Cmp(...)
        })
        
        t.Run("bar", func(t *td.T) {
            // already parallel
            t.Cmp(...)
        })
    }
    

    But that can be a separate discussion.

    opened by abhinav 3
  • deepValueEqual infinite recursion with recursive map types

    deepValueEqual infinite recursion with recursive map types

    I've found an infinite recursion case with go-testdeep. It's a bit contrived I know; I was actually trying to break things. I'm currently developing an encoding library and trying to break it with test cases galore. Interestingly enough encoding/gob, reflect.DeepEqual (fixed in go1.15), and every 3rd party library I've found suffers from this same issue.

    If given a map containing a struct that contains the same map, deepValueEqual recuses infinitely.

    This test case reproduces the issue

    func TestEqualRecursMap(t *testing.T) {
    	gen := func() interface{} {
    		type S struct {
    			Map map[int]S
    		}
    
    		m := make(map[int]S)
    		m[1] = S{
    			Map: m,
    		}
    
    		return m
    	}
    
    	checkOK(t, gen(), gen())
    }
    

    Thanks so much for your work. Let me know if I can help.

    opened by stewi1014 3
  • feat(Code): Code can now officially delegate its comparison

    feat(Code): Code can now officially delegate its comparison

    Using two new kinds of function:

    • func(t *td.T, arg)
    • func(assert, require *td.T, arg)

    this way the usage of *td.T methods is secure. Note that these functions do not return anything.

    At the same time, using a *td.T instance as Cmp* first parameter allows to inherit its configuration.

    td.Cmp(td.Require(t), got, 42)
    

    is the same as:

    td.Require(t).Cmp(got, 42)
    
    opened by maxatome 2
  • fix(tdsuite): detect wrongly defined hooks

    fix(tdsuite): detect wrongly defined hooks

    Given the 5 hooks:

    • Setup
    • PreTest
    • PostTest
    • BetweenTests
    • Destroy raise an error when a method is defined on a tdsuite with one of these names but without matching the proper interface.
    opened by deathiop 2
  • anchors not working with table driven tests / multiple t.Cmp calls

    anchors not working with table driven tests / multiple t.Cmp calls

    I'm building some Stripe tests with large, deeply nested structs, where using anchors is very helpful. They work great when I have a single test, but if I'm calling t.Cmp multiple times or have table driven tests, anchors are being compared against the wrong values. Since the anchors have to be set outside the inner test run loop, I'm not sure how td knows when to iterate between them. Am I doing something incorrectly?

    Table driven test

    func Test_payInvoiceWithStripe(stdT *testing.T) {
    	tdt := td.NewT(stdT)
    
    	tests := []struct {
    		name                  string
    		stripeCustomerID      string
    		stripePaymentMethodID string
    		wantPaymentIntent     *stripe.PaymentIntent
    		wantErr               error
    	}{
    		// lots of tdt.A
    	}
    
    	stripeClient := client.New(apiKey, nil)
    	invoice := &billingpb.Invoice{
    		InvoiceId:            111,
    		AccountId:            22222,
    	}
    
    	for i, tt := range tests {
    		tdt.Run(tt.name, func(t *td.T) {
    			gotPaymentIntent, err := chargeCustomer(context.Background(), stripeClient, tt.stripeCustomerID, tt.stripePaymentMethodID, invoice, int64(i))
    			if tt.wantErr == nil {
    				t.CmpNoError(err)
    			} else {
    				t.Cmp(e.Cause(err).(*stripe.Error), e.Cause(tt.wantErr).(*stripe.Error))
    			}
    			t.Cmp(gotPaymentIntent, tt.wantPaymentIntent)
    		})
    	}
    

    Output

            DATA.ChargeID: values differ
            	     got: "ch_3KH0DO4HQ2O7mN7V1o3cxNfi"
            	expected: "<[email protected]#12>"
    

    Thanks for a great library!

    opened by derekperkins 2
  • feat(fatalizer): operators do not panic anymore

    feat(fatalizer): operators do not panic anymore

    Get rid of fatalizer, if an operator can not be built, it raises an error during the next Match() attempt.

    This way, we don't need to panic anymore, and so the user is not disappointed by a sometimes hard-to-read stack trace, erroneously thinking the fault comes from go-testdeep.

    opened by maxatome 2
  • Add support for quotation marks in JSON operators

    Add support for quotation marks in JSON operators

    Problem: We use different operators in JSONs which are then used for comparison. If we add regular operators to json string, e.g. Len, HasPrefix, etc, the JSON becomes invalid and formatters, validators cannot parse the string.

    Proposal: Add support for quotation marks for operators in JSON strings, similarly to currently it is being used for shortcut operators "$^NotEmpty". Ideally it could look similar "$^Len(10)"

    enhancement 
    opened by r6q 3
  • Add comparison to github.com/go-test/deep

    Add comparison to github.com/go-test/deep

    It would be helpful to have a comparison table or something in the readme to help people understand the difference between this package and https://github.com/go-test/deep. That has more stars and shows up better in search, while this library seems much more active.

    documentation 
    opened by derekperkins 3
  • Expose some internal types, so custom operators can be built

    Expose some internal types, so custom operators can be built

    The request in a nutshell: can enough internal details be exposed to allow building custom operators externally? Ideally in a stable way.

    I very much realize this is not a simple request, but someone has to make it :) Maybe it can serve as a placeholder for planning / discussion. Some context / broader reasoning is below.


    TestDeep looks super interesting! From a quick glance it looks like there are a lot of good, flexible, well-thought-out features, especially around good error messages (that's so rare, thank you!).

    While there are quite a few built-in operators, there are always some edge cases that benefit from custom ones. The JSON operators serve as a nice example of this: it's just a string, but there's a lot of structure that can imply much-better error reporting and a simpler API, so it has a custom operator to improve things.
    Unfortunately, though td/types.go exposes the TestDeep interface, the base type is not exposed, and location.GetLocationer deals with the (afaict) internal-only Location type, so custom operators cannot be built outside this library. There may be other causes as well, this one was just one I saw while reading.

    This is... probably a very reasonable choice for API stability, but somewhat crippling for less-common needs. I assume you don't want to collect every ill-advised and poorly-implemented operator that every user/company/etc dreams up, so being able to build things from the outside would be great. It could also enable "enriching" libraries that enhance TestDeep.

    Is there a way this can be done?

    opened by Groxx 1
Releases(v1.12.0)
  • v1.12.0(Aug 7, 2022)

    New features

    • Struct & SStruct can override model fields in expectedFields, as in:
        td.Cmp(t, got, td.Struct(
          Person{
            Name:     "John Doe",
            Age:      23,
            Children: 4,
          },
          td.StructFields{
            "> Age":     td.Between(40, 45),
            ">Children": 0, // spaces after ">" are optional
          }),
        )
      
    • Struct & SStruct expectedFields is now optional or multiple. If multiple, all maps are merged from left to right;
    • try to detect wrongly defined hooks in tdsuite @deathiop Given the 5 hooks:
    • try to detect possible tdsuite.Run() misuse, warn the user when it is called with a non-pointer suite, and some key methods are only available via a pointer suite;
    • add tdhttp.Options function & tdhttp.TestAPI.Options method;
    • Code can now officially delegate its comparison, using two new kinds of function:
      • func(t *td.T, arg)
      • func(assert, require *td.T, arg) this way the usage of *td.T methods is secure. Note that these functions do not return anything;
    • using a *td.T instance as Cmp* first parameter now allows to inherit its configuration.
      td.Cmp(td.Require(t), got, 42)
      

      is the same as:

      td.Require(t).Cmp(got, 42)
      

    Fixes

    Miscellaneous

    • enhance & refactor doc comments with new go 1.19 features;
    • documentation now uses any instead of interface{};
    • fix typos.

    As usual: enjoy! :)

    Source code(tar.gz)
    Source code(zip)
  • v1.11.0(Jan 5, 2022)

    New features

    • JSON, SubJSONOf and SuperJSONOf operators:
      • Now:
        td.JSON(`{"foo": $1}`, td.Between(12, 34))
        td.JSON(`{"foo": Between($1, $2)}`, 12, 34)
        

        act the same way. Since v1.10.1 rework, the second was not working as expected.
        At the same time:

        td.JSON(`{"foo": Between(12, 34, $1)}`, td.BoundsOutIn)
        

        now works as expected. It was rejected before,

      • int_lit & float_lit numbers, as defined in go specification, are now accepted in JSON, allowing, for example, to embed hexadecimal numbers in expected JSON;
    • Between operator accepts time.Duration as TO when FROM is a time.Time;
    • Between, Gt, Gte, Lt and Lte operators:
      • now handle values implementing Compare or Less methods:
        Compare and/or Less methods signatures follow:
        func (a T) Less(b T) bool   // returns true if a < b
        func (a T) Compare(b T) int // returns -1 if a < b, 1 if a > b, 0 if a == b
        

        for example, the new go1.18 net/netip.Addr implements both,

      • failure reports display numbers as elsewhere,
      • some docs have been fixed;
    • Smuggle can now cast values, allowing such things:
      // A string containing JSON
      got := `{ "foo": 123 }`
      td.Cmp(t, got, td.Smuggle(json.RawMessage{}, td.JSON(`{"foo":123}`))
      // or
      td.Cmp(t, got, td.Smuggle((json.RawMessage)(nil), td.JSON(`{"foo":123}`))
      
    • in report failures, the stack trace was displayed if it contained at least 2 levels. Now it is also displayed if it contains one level BUT the source file path contains a directory. It helps to localize quickly the errors in large repositories;
    • td.T gains 3 new methods to log with a stack trace: LogTrace, ErrorTrace and FatalTrace;
    • handle go1.17 []T*[n]T convertibility edge case;
    • in failure reports (float64) type is now omitted (like (int) and (bool) already were), but the value always contains a "." (except if ±Inf, NaN or with exponent) to distinguish them from int.

    Fixes

    • Contains: slice in slice search didn't work at end of slice;
    • JSON, SubJSONOf and SuperJSONOf operators panicked when using All+JSON-operator+embeddedOp+$1;
    • anchoring 2 slices at the same time didn't work.

    Miscellaneous

    And happy new year!

    Source code(tar.gz)
    Source code(zip)
  • v1.10.1(Sep 27, 2021)

    Fixes:

    • Len and Cap could not be embedded in JSON, SubJSONOf and SuperJSONOf. Fixed;
    • Bag and Set didn't implement TypeBehind() method. Fixed;
    • JSONPointer expectedValue and JSON placeholders didn't have the same behavior. Now the pointed data is JSON-unmarshaled into a value using the same type of expectedValue (for JSONPointer) or any placeholder (for JSON) before comparison;
    • Catch TypeBehind() method didn't use the type of target when the type behind expectedValue could not be determined. Fixed;
    • (*tdhttp.TestApi).CmpJSONBody(nil) panicked. Fixed;
    • and some typos fixed.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.10.0(Aug 31, 2021)

    New features:

    Fixes:

    • multi-lines colored text → color-off \n color-on for each line (@siadat);
    • JSON TypeBehind() method is now delegated when an operator is at the root of the JSON;
    • tdhttp package:
      • chaining of Cmp* methods can lead to skew Failed() result.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.9.2(Mar 18, 2021)

  • v1.9.1(Mar 16, 2021)

    Fixes:

    • traces displayed when a Cmp failure occurs, are now properly stripped to ignore testing, td, tdhttp and tdsuite internal calls;
    • JSON unmarshal bug when \uxxxx is first escaping sequence in a string.
    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Mar 9, 2021)

    New features:

    • introducing new tdsuite helper, allowing to easily create testing suites, fully integrated with go-testdeep;
    • JSON, SubJSONOf and SuperJSONOf now accept almost all operators embedded directly in JSON thanks to our new custom JSON decoder:
      td.Cmp(t,
        got,
        td.JSON(`{"name": HasPrefix("Bob"), "age": Between(20, 25)}`),
      )
      
    • Re and ReAll capture parameter can now be a []interface{} (only []string until now);
    • Flatten is now able to flatten maps, can be useful when creating request using tdhttp package;
    • when a Cmp failure occurs outside the root of a test function, a trace of all successive function calls is displayed to help the user to understand/locate the error;
    • in tdhttp helper (aka the ultimate HTTP API tester), tdhttp.TestAPI gains several methods:
      • AutoDumpResponse allows to dump the HTTP response when the first error is encountered after a request,
      • OrDumpResponse dumps the response if at least one previous test failed,
      • Run runs a subtest,
      • T returns the internal instance of *td.T,
      • With creates a new *TestAPI instance.

    Fixes:

    • reflect.Interface containing nil could produce wrong comparisons.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Dec 17, 2020)

    New features:

    • add new JSONPointer operator following RFC 6901;
    • when 2 types differ but have the same short name, use full pkg name in error report;
    • add Cmp and Smuggle hooks feature;
    • new td.Tuple type added and its td.TupleFrom() builder. Useful to quickly test functions returning several values as in:
      price := func(p float64) (float64, string, error) {
        if p < 0 {
          return 0, "", errors.New("negative price not supported")
        }
        return p * 1.2, "€", nil
      }
      
      td.Cmp(t,
        td.TupleFrom(price(10)),
        td.TupleFrom(float64(12), "€", nil),
      )
      
      td.Cmp(t,
        td.TupleFrom(price(-10)),
        td.TupleFrom(float64(0), "", td.Not(nil)),
      )
      
    • when calling tdhttp.NewRequest() (and all other request builder methods) headers can be flattened with td.Flatten().

    Fixes:

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Jul 19, 2020)

    New features:

    • new (*td.T).RunAssertRequire function. Useful to avoid boilerplate code:
      t.RunAssertRequire("GetAge", func (assert *td.T, require *td.T) {
        age, err := GetAge("Bob")
        require.CmpNoError(err)
        assert.Cmp(age, 42)
      })
      
    • new tdhttp.TestAPI method Or(), useful to debug a test failure:
      ta.Get("/person/42", "Accept", "application/json").
        CmpJSONBody(td.JSON(`{"id": $1, "name": "Bob"}`, td.NotZero())).
        Or(func (body string) { t.Logf("received unexpected body: <%s>", body) })
      

      see the Or() documentation as the passed function can have a much more complex signature. It is inspired by Test::Mojo or() method and allows to easily inspect the response of the requested API when the checks fail.

    Fixes:

    • #101 → some data recursion cases were not correctly handled (reported and tested by @stewi1014);
    • some panics due to the user misbehavior were not properly red-colored;
    • (*td.T).Run: t.Config is now copied instead of shared before using it in sub-func;
    • typos in doc.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(May 31, 2020)

    Changes:

    • td.TestingFT interface is deprecated (but still usable) and superseded by testing.TB standard one: it allows to work with *testing.B instances as well (or any other type implementing testing.TB);
    • (*td.T).RunT() is deprecated (but still usable) and superseded by (*td.T).Run() which now delegates to td.T.TB if it implements a Run() method with the following signature:
      (X) Run(string, func(X)) bool
      

    Breaking changes:

    • as td.TestingFT interface is now an alias on testing.TB, it does not contain Run(string, func (*testing.T)) bool anymore;
    • it is quite unlikely that (*td.T).Run(string, func (*testing.T)) method is used, but if it is, all calls have to be replaced by (*td.T).Run(string, func (*td.T)) like in:
      tt.Run("my_test", func (tt *td.T) {
          t := tt.TB.(testing.T)
          ...
      })
      

      note that even though (*td.T).RunT() is deprecated, it still works as expected.

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(May 17, 2020)

    New features:

    • new Flatten function: useful to flatten non interface{} slices in Set, Bag arguments (but not only, read the doc);
    • panic messages due to user misuse of go-testdeep functions/methods are now red colored to help her/him to focus on her/his mistake and not think go-testdeep failed shamefully;
    • delay colors initialization to the first use. So colors can now be disabled in golang playgroung. See the corresponding FAQ point;
    • optimize some type retrievals.

    Fix:

    • forbid Isa(nil) because it is a nonsense and so avoid a deep panic.

    New FAQ entries:

    Enjoy and do not forget to star!

    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Apr 11, 2020)

  • v1.3.0(Feb 29, 2020)

    Package github.com/maxatome/go-testdeep is deprecated, it is recommended to use github.com/maxatome/go-testdeep/td in new code.

    github.com/maxatome/go-testdeep is still usable so the compatibility is preserved.

    The only breaking change is the disappearance of testdeep.DefaultContextConfig. It should be replaced by td.DefaultContextConfig and so the go-testdeep import line should be changed (at least "github.com/maxatome/go-testdeep/td" should be added).

    To summarize: migration to github.com/maxatome/go-testdeep/td is not needed, only recommended, except if testdeep.DefaultContextConfig is used.

    To migrate:

    import "github.com/maxatome/go-testdeep"
    …
    testdeep.DefaultContextConfig = testdeep.ContextConfig{…}
    testdeep.Cmp(…)
    

    or with "td" package alias:

    import td "github.com/maxatome/go-testdeep"
    …
    td.DefaultContextConfig = td.ContextConfig{…}
    td.Cmp(…)
    

    simply do (see import line changes):

    import "github.com/maxatome/go-testdeep/td"
    …
    td.DefaultContextConfig = td.ContextConfig{…}
    td.Cmp(…)
    

    See the FAQ point for details about this migration.

    And still, do not forget to visit https://go-testdeep.zetta.rocks/ and open an issue if something seems to be missing or not clear.

    Happy testing!

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Feb 13, 2020)

  • v1.1.2(Nov 18, 2019)

    New features:

    Synopsis revisited!

    Enjoy powerful API testing!

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Nov 3, 2019)

  • v1.1.0(Jul 7, 2019)

    New features:

    Breaking changes:

    Bugs fixes:

    • Fix a bug when compared slices have the same backend array.

    Misc:

    Source code(tar.gz)
    Source code(zip)
  • v1.0.8(Jan 14, 2019)

  • v1.0.7(Dec 10, 2018)

  • v1.0.6(Dec 7, 2018)

  • v1.0.5(Nov 2, 2018)

  • v1.0.3(Aug 19, 2018)

    • internal structures not accessible anymore
    • works around golang https://github.com/golang/go/issues/26995 issue (impact go test -race usages)
    • unit tests pass when "unsafe" package is not available
    • test coverage increased
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Jul 20, 2018)

  • v1.0.1(Jul 15, 2018)

  • v1.0.0(Jun 24, 2018)

Testing framework for Go. Allows writing self-documenting tests/specifications, and executes them concurrently and safely isolated. [UNMAINTAINED]

GoSpec GoSpec is a BDD-style testing framework for the Go programming language. It allows writing self-documenting tests/specs, and executes them in p

Esko Luontola 113 Sep 2, 2022
A next-generation testing tool. Orion provides a powerful DSL to write and automate your acceptance tests

Orion is born to change the way we implement our acceptance tests. It takes advantage of HCL from Hashicorp t o provide a simple DSL to write the acceptance tests.

Wesovi Labs 45 Aug 31, 2022
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

GoConvey is awesome Go testing Welcome to GoConvey, a yummy Go testing tool for gophers. Works with go test. Use it in the terminal or browser accordi

SmartyStreets 7.4k Sep 23, 2022
Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.

GoConvey is awesome Go testing Welcome to GoConvey, a yummy Go testing tool for gophers. Works with go test. Use it in the terminal or browser accordi

SmartyStreets 7.4k Sep 23, 2022
Record and replay your HTTP interactions for fast, deterministic and accurate tests

go-vcr go-vcr simplifies testing by recording your HTTP interactions and replaying them in future runs in order to provide fast, deterministic and acc

Marin Atanasov Nikolov 944 Sep 25, 2022
A simple and expressive HTTP server mocking library for end-to-end tests in Go.

mockhttp A simple and expressive HTTP server mocking library for end-to-end tests in Go. Installation go get -d github.com/americanas-go/mockhttp Exa

Americanas Go 6 Dec 19, 2021
HTTP mock for Golang: record and replay HTTP/HTTPS interactions for offline testing

govcr A Word Of Warning I'm in the process of partly rewriting govcr to offer better support for cassette mutations. This is necessary because when I

Seb C 131 Sep 27, 2022
Package for comparing Go values in tests

Package for equality of Go values This package is intended to be a more powerful and safer alternative to reflect.DeepEqual for comparing whether two

Google 3.1k Sep 22, 2022
Package has tool to generate workload for vegeta based kube-api stress tests.

Package has tool to generate workload for vegeta based kube-api stress tests.

Mikhail Sakhnov 0 Nov 22, 2021
siusiu (suite-suite harmonics) a suite used to manage the suite, designed to free penetration testing engineers from learning and using various security tools, reducing the time and effort spent by penetration testing engineers on installing tools, remembering how to use tools.

siusiu (suite-suite harmonics) a suite used to manage the suite, designed to free penetration testing engineers from learning and using various security tools, reducing the time and effort spent by penetration testing engineers on installing tools, remembering how to use tools.

Re 271 Sep 13, 2022
A yaml data-driven testing format together with golang testing library

Specimen Yaml-based data-driven testing Specimen is a yaml data format for data-driven testing. This enforces separation between feature being tested

Design it, Run it 0 Jan 31, 2022
📡 mock is a simple, cross-platform, cli app to simulate HTTP-based APIs.

mock ?? mock is a simple, cross-platform, cli app to simulate HTTP-based APIs. About mock Mock allows you to spin up a local http server based of a .m

Bruno Schaatsbergen 8 May 6, 2022
Golang application focused on tests

Maceio Golang application that listens for webhook events coming from Github, runs tests previously defined in a configuration file and returns the ou

Leonardo Damasceno 5 Sep 8, 2021
S3 etag tests for golang

S3-etag-tests Quickstart Run docker-compose up. Execute tests in /test with $ go

null 0 Dec 16, 2021
Behaviour Driven Development tests generator for Golang

gherkingen It's a Behaviour Driven Development (BDD) tests generator for Golang. It accept a *.feature Cucumber/Gherkin file and generates a test boil

Maxim Krivchun 49 Sep 22, 2022
Robust framework for running complex workload scenarios in isolation, using Go; for integration, e2e tests, benchmarks and more! 💪

e2e Go Module providing robust framework for running complex workload scenarios in isolation, using Go and Docker. For integration, e2e tests, benchma

null 114 Sep 23, 2022
How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race. The basic

amyangfei 1 Oct 31, 2021
Snapshot - snapshot provides a set of utility functions for creating and loading snapshot files for using snapshot tests.

Snapshot - snapshot provides a set of utility functions for creating and loading snapshot files for using snapshot tests.

Daniel J. Rollins 2 Jan 27, 2022
Ruby on Rails like test fixtures for Go. Write tests against a real database

testfixtures Warning: this package will wipe the database data before loading the fixtures! It is supposed to be used on a test database. Please, doub

null 849 Sep 14, 2022