Skip to content

Instantly share code, notes, and snippets.

@mvndaai
Last active May 27, 2020 03:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mvndaai/54d13611d62e8fa9306bdd11a2bb4666 to your computer and use it in GitHub Desktop.
Save mvndaai/54d13611d62e8fa9306bdd11a2bb4666 to your computer and use it in GitHub Desktop.
Go table test
package tabletest
import "errors"
//ForceError will return an error if the boolean is true
func ForceError(force bool) error {
if force {
return errors.New("forced error")
}
return nil
}
package tabletest
import (
"testing"
)
func TestWithTables(t * testing.T){
tests := []struct{
name string
expectedError bool
forceError bool
}{
{name: "pass without error", expectedError: false, forceError: false},
{name: "pass with error", expectedError: true, forceError: true},
{name: "fail without error", expectedError: true, forceError: false},
{name: "fail with error", expectedError: false, forceError: true},
{name: func()string{
/*
Sometimes you want to use a function to generate a happy object for all tests and then change one thing about it
This is complicated in a table test because multiple lines of code is not usually expected in initiating a struct
If you make an anonymous function, like this, you can call your function to create a happy object
After editing it, return the new object
Since there is the () after the {} it is returned immediately
ex: h := happyObject(); h.value = "change"; return h;
*/
return "name from function"
}(),
expectedError: false, forceError: false},
}
for _, test := range tests {
// `t.Run` appends the name to a test and makes a fatal only relate to the specific test
// See the output below to see how much it simplifies finding issues
t.Run(test.name, func(t *testing.T){
//If a test is safe to run concurrently you can use `t.Parallel()`
defer func(){
if t.Failed(){
t.Log("extra logging only if failed, not shown when running verbose tests")
}
/*
Wrapping `t.Log` in `if t.Failed()` makes sure this is only logged if the test has already failed
This helps keep logs clean when running in verbose mode
Wrapping this in a `defer` is a trick to make the additonal logging always show on failures
This is especially helpful when using `t.Fatal`
*/
}()
err := ForceError(test.forceError)
if (err != nil) != test.expectedError {
t.Fatal("Error was not expected:", err)
// `t.Fatal` stops the test here. If you want it to continue after an error use `t.Error`
}
})
}
}
/* Output of `go test ./... -v`
--- FAIL: TestWithTables (0.00s)
--- PASS: TestWithTables/pass_without_error (0.00s)
--- PASS: TestWithTables/pass_with_error (0.00s)
--- FAIL: TestWithTables/fail_without_error (0.00s)
tabletest_test.go:45: Error was not expected: <nil>
tabletest_test.go:39: extra logging only if failed, not shown when running verbose tests
--- FAIL: TestWithTables/fail_with_error (0.00s)
tabletest_test.go:45: Error was not expected: forced error
tabletest_test.go:39: extra logging only if failed, not shown when running verbose tests
--- PASS: TestWithTables/name_from_function (0.00s)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment