catch

package module
v1.4.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 23, 2023 License: BSD-3-Clause Imports: 13 Imported by: 0

README

logo Package catch

Testing with better error messages and less code.

Package catch provides utility functions that work with the standard library's testing capabilities. The functions encapsulate standard tests, and standardize logging for failures. However, package catch does not output anything directly. All messages are formatted using the standard methods on the test object.

  • Simple, lean API that handles the formatting of all error messages.
  • Does not replace *testing.T, and can be mixed freely with other test code using the standard library.
  • Easily annotate tests with comments or additional fields.

As an example, when the following test fails:

func TestFancyCalculation(t *testing.T) {
    fancyCalculation := 1 + 1
    catch.CheckEqual(t, fancyCalculation, 1)
}

The log will be:

example_test.go:99: check failed: fancyCalculation == 1
        expected : 1
        got      : 2

The source files for the test code should be available and unmodified at their original locations when the tests are run. The source code is read and parsed to create messages for any failed tests. If the source code is not available, tests can still be run, but the messages for any failed tests will not be complete.

Install

Go version 1.9 or later is required. The package can be installed from the command line using the go tool.

go get gitlab.com/stone.code/catch

This package will not work with go version 1.8 or earlier. It depends on the method Helper for testing.B and testing.T to properly format messages.

Getting Started

Package documentation and examples are on godoc.

Contribute

Feedback and PRs welcome. You can also submit an issue.

This package is considered to be complete, but additional checks may be considered. The main criteria for a new function will be if it can provide a better message when the test fails. However, other types of utility functions are probably out-of-scope.

Go Report Card

Benchmarking

While performance is not a primary concern, the performance for generating messages is monitored. Currently, logging with this package does not incur significant overhead compared with hand-written calls to testing.T.Logf and family. In addition to the standard go test, please verify the benchmarks for any changes.

License

BSD (c) Robert Johnstone

Documentation

Overview

Package catch provides utility functions that work with the standard library's testing capabilities. The functions encapsulate standard tests, and standardise logging for failures. However, package catch does not output anything directly. All messages are formatted using the standard methods on the test object.

As an example, when the following test fails:

func TestFancyCalculation(t *testing.T) {
    fancyCalculation := 1 + 1
    catch.CheckEqual(t, fancyCalculation, 1)
}

The log will be:

testing_test.go:285: check failed: fancyCalculation == 1
        got      : 2
        expected : 1

The source files for the test code should be available and unmodified at their original locations when the tests are run. The source code is read and partially parsed to create messages for any failed tests. If the source code is not available, tests can still be run, but the messages for any failed tests will not be complete.

Message Formatting and Annotation

When a test fails, package catch will create an error message based on the user's source code. The source code for the helper's caller will be opened, and the expression for the arguments included in the error report.

If the line with error contains a line comment, the line comment will also be included in the error message.

User's can also add an arbitrary number of arguments to any call. Those arguments are not used for the test, but will be included in the message if the test fails. With this facility, users can easily add important context to failing tests.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Check

func Check(t TB, value bool, fields ...interface{})

Check does nothing if 'value' is true, but will a report an error if it is false. The error is reported using Errorf, meaning that the error will be logged and the test will be marked as failing.

Example
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.Check(t, fancyResult == 2)
	})
}
Output:

Example (Annotations)
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	// This example shows the two ways to annotate a test with extra
	// information.  First, extra parameters are included in the error message
	// if the test fails.  Second, line comments after the closing parenthesis
	// are also included in the error message.
	testing.Run("Example", func(t *testing.T) {
		const message = "A message"
		const value = 1234

		// Test setup goes here.
		// ...
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.Check(t, fancyResult == 3, message, value) // Comment that explains the test.
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: check failed: fancyResult == 3
        message  : A message
        value    : 1234
        comment  : Comment that explains the test.
Example (Fail)
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.Check(t, fancyResult == 3)
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: check failed: fancyResult == 3

func CheckEqual

func CheckEqual(t TB, got, expected interface{}, fields ...interface{})

CheckEqual does nothing if 'expected' and 'got' are equal, but will a report an error otherwise. The error is reported using Errorf, meaning that the error will be logged and the test will be marked as failing.

Example
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.CheckEqual(t, fancyResult, 2)
	})
}
Output:

Example (Err)
package main

import (
	"errors"

	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		err := errors.New("custom error")

		// Make sure that the result is expected.
		catch.CheckEqual(t, err, nil)
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: check failed: err == nil
        got      : custom error
        expected : <nil>
Example (Fail)
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.CheckEqual(t, fancyResult, 3)
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: check failed: fancyResult == 3
        got      : 2
        expected : 3

func CheckIsNil added in v1.1.0

func CheckIsNil(t TB, got interface{}, fields ...interface{})

CheckIsNil does nothing if 'got' is a nil chan, func, map, pointer, or slice value, but will a report an error otherwise. The error is reported using Errorf, meaning that the error will be logged and the test will be marked as failing.

This function can only be called with chan, func, map, pointer, or slice values. It will panic otherwise.

Example
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		var s []byte

		// Make sure that the result is expected.
		catch.CheckIsNil(t, s)
	})
}
Output:

Example (Fail)
package main

import (
	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Test setup goes here.
		// ...
		s := make([]byte, 0)

		// Make sure that the result is expected.
		catch.CheckIsNil(t, s)
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: check is nil failed: s
        got      : []

func Require

func Require(t TB, value bool, fields ...interface{})

Require does nothing if 'value' is true, but will a report an error if it is false. The error is reported using Fatalf, meaning that the error will be logged and the test will fail immediately.

Example
package main

import (
	"os"

	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Open file with test data.  Abort the test if the file cannot be
		// opened.
		file, err := os.Open("required-test-data.txt")
		catch.Require(t, err == nil)
		// The error must be nil.  Otherwise, test would have been aborted by the
		// previous call to Require would have aborted the test.
		defer file.Close()

		// Count the number of lines in the file.
		fancyResult := 1 + 1

		// Make sure that the result is expected.
		catch.Require(t, fancyResult == 2)
	})
}
Output:

Example (Fail)
package main

import (
	"fmt"

	"gitlab.com/stone.code/catch"
	testing "gitlab.com/stone.code/catch/internal/mock"
)

func main() {
	testing.Run("Example", func(t *testing.T) {
		// Perform terribly complicated calculations.
		fancyResult := 1 + 2

		// Make sure that the result is expected.
		catch.Require(t, fancyResult == 2)

		// This will never print, as the test will be aborted.
		fmt.Println("done.")
	})

}
Output:

--- FAIL: Example (0.00s)
    example.go:99: require failed: fancyResult == 2

func RequireEqual

func RequireEqual(t TB, got, expected interface{}, fields ...interface{})

RequireEqual does nothing if 'expected' and 'got' are equal, but will a report an error otherwise. The error is reported using Fatalf, meaning that the error will be logged and the test will fail immediately.

func RequireIsNil added in v1.1.0

func RequireIsNil(t TB, got interface{}, fields ...interface{})

RequireIsNil does nothing if 'got' is a nil chan, func, map, pointer, or slice value, but will a report an error otherwise. The error is reported using Fatalf, meaning that the error will be logged and the test will fail immediately.

This function can only be called with chan, func, map, pointer, or slice values. It will panic otherwise.

Types

type TB

type TB interface {
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
	Logf(format string, args ...interface{})
	Helper()
}

TB is a subset of the interface testing.TB. These methods are the portion of that interface required for the checks.

Directories

Path Synopsis
internal
cache
Package cache maintains a cache of parsed Go source files.
Package cache maintains a cache of parsed Go source files.
polyfill
Package polyfill supplies a polyfill for token.File.LineStart, introduced with Go version 1.12.
Package polyfill supplies a polyfill for token.File.LineStart, introduced with Go version 1.12.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL