justest

package module
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Jun 23, 2024 License: MIT Imports: 22 Imported by: 1

README

justest

Maintainer GoVersion GoDoc GoReportCard

Go testing framework with extra sugar

This Go testing framework has the following goals:

  • Play nice with go test
  • Provide a fluent API for making assertions
  • Provide a succinct yet informative error information on failures
  • Make testing easier to read and write

Attribution

This library is heavily inspired by Gomega and Ginkgo, two excellent Go testing libraries that I've used extensively in the past. If you need a full standalone (see below) BDD testing framework, those are highly recommended.

The reason Justest was created is because Gomega and Ginkgo do not play great with go test (though Gomega does have a go test integration, it's still primarily meant to be used with Ginkgo) whereas Justest is meant all along to be used with go test.

Usage

package my_test

import (
	"fmt"
	"regexp"
	"testing"
	"time"

	. "github.com/arikkfir/justest"
)

func TestSomething(t *testing.T) {
	
	// Simple assertions
	With(t).VerifyThat(1).Will(BeBetween(0, 2)).Now()
	With(t).VerifyThat("").Will(BeEmpty()).Now()
	With(t).VerifyThat([]int{1, 2, 3}).Will(BeEmpty()).Now() // <-- This will fail!
	With(t).VerifyThat(1).Will(BeGreaterThan(0)).Now()
	With(t).VerifyThat(1).Will(BeLessThan(2)).Now()
	With(t).VerifyThat("abc").Will(BeNil()).Now() // <-- This will fail!
	With(t).VerifyThat(1).Will(EqualTo(1)).Now()
	With(t).VerifyThat("abc").Will(EqualTo("def")).Now() // <-- This will fail!

	// Assert success or failure of a function (functions can have any set of return values or none at all)
	succeedingFunc := func() (string, error) { return "abc", nil }
	With(t).VerifyThat(succeedingFunc).Will(Succeed()).Now() // <-- Will succeed since error return value is nil
	With(t).VerifyThat(succeedingFunc).Will(Fail()).Now()    // <-- Will fail since it expects error return value to be non-nil
	failingFunc := func() (string, error) { return "", fmt.Errorf("error") }
	With(t).VerifyThat(failingFunc).Will(Succeed()).Now() // <-- Will fail since error return value is not nil
	With(t).VerifyThat(failingFunc).Will(Fail()).Now()    // <-- Will succeed since it expects error return value to be non-nil

	// Assert negation of another assertion
	With(t).VerifyThat(1).Will(Not(EqualTo(2))).Now()
	
	// Assert something will **eventually** match
	// It will stop when the function succeeds (no assertion failure) or when time runs out
	With(t).VerifyThat(func(t T) {

		// Will be invoked every 100ms until either it no longer fails or until time runs out (10s)
		With(t).VerifyThat(2).Will(EqualTo(2)).Now()

	}).Will(Succeed()).Within(10*time.Second, 100*time.Millisecond)

	// Assert something will **repeatedly** match for a certain amount of time
	// It will stop on the first time the function fails
	With(t).VerifyThat(func(t T) {

		// Will be invoked every 100ms until either it fails or until time runs out (10s)
		With(t).VerifyThat(2).Will(EqualTo(2)).Now()

	}).Will(Succeed()).For(10*time.Second, 100*time.Millisecond)

	// Assert on text patterns
	With(t).VerifyThat("abc").Will(Say("^a*c$")).Now()
	With(t).VerifyThat("abc").Will(Say(regexp.MustCompile("^a*c$"))).Now()
	With(t).VerifyThat([]byte("abc")).Will(Say("^a*c$")).Now()
}

Custom matchers

You can easily create your own matchers by implementing the Matcher interface:

package my_test

import (
	"reflect"

	. "github.com/arikkfir/justest"
)

var (
	myValueExtractor = NewValueExtractor(ExtractSameValue)
)

// BeSuperDuper returns a matcher that will ensure that each actual value passed to "With(t).VerifyThat(...)" will be either
// "super duper" or "extra super duper", depending on the value of the `extraDuper` parameter.
func BeSuperDuper(extraDuper bool) Matcher {
	return MatcherFunc(func(t T, actuals ...any) {
		GetHelper(t).Helper()
		for _, actual := range actuals {
			v := myValueExtractor.MustExtractValue(t, actual) // This is optional, but recommended, see value extraction below
			if extraDuper {
				// Fail if it's not EXTRA super-duper
				if v.(string) != "extra super duper" {
					t.Fatalf("Value '%s' is not extra super-duper!", v)
				}
			} else {
				// Fail if it's not super-duper
				if v.(string) != "super duper" {
					t.Fatalf("Value '%s' is not super-duper!", v)
				}
			}
		}
	})
}

Builtin matchers

Matcher Name Description
BeBetween(min, max) Checks that all given values are between a minimum and maximum value
BeEmpty() Checks that all given values are empty
BeGreaterThan(min) Checks that all given values are greater than a minimum value
BeLessThan(max) Checks that all given values are less than a maximum value
BeNil() Checks that all given values are nil
EqualTo(expected) Checks that all given values are equal to their corresponding expected value
Fail() Checks that the last given value is a non-nil error instance
Not() Checks that the given matcher fails
Say() Checks that all given values match the given regular expression
Succeed() Checks that the last given value is either nil or not an error instance

Contributing

Please do 👌 💪 !

See CONTRIBUTING.md for more information 🙏

Documentation

Index

Constants

View Source
const SlowFactorEnvVarName = "JUSTEST_SLOW_FACTOR"

Variables

View Source
var (
	NumericValueExtractor = NewNumericValueExtractor()
)

Functions

func ExtractSameValue

func ExtractSameValue(t T, v any) (any, bool)

func ExtractorUnsupported

func ExtractorUnsupported(t T, v any) (any, bool)

func GetHelper

func GetHelper(t T) interface{ Helper() }

func GetRoot added in v0.1.0

func GetRoot(t T) *testing.T

Types

type Asserter

type Asserter interface {
	Will(m Matcher) Assertion
}

type Assertion

type Assertion interface {
	// Now will perform the assertion and fail immediately if it mismatches.
	Now()

	// Deprecated: OrFail is a synonym for Now.
	OrFail()

	// For will continually perform the assertion until the given duration has passed or until it mismatches. If it
	// mismatched once, the assertion is considered failed.
	For(duration time.Duration, interval time.Duration)

	// Within will continually perform the assertion until the given duration has passed or until it successfully
	// matches. If the duration has passed without any successful matches, the assertion is considered failed.
	Within(duration time.Duration, interval time.Duration)
}

type Comparator

type Comparator func(t T, expected any, actual any)

type Ensurer added in v0.7.0

type Ensurer interface {
	ByVerifying(actuals ...any) Asserter
}

type EqualToMatcher

type EqualToMatcher interface {
	Matcher
	Using(comparator Comparator) EqualToMatcher
}

func EqualTo

func EqualTo(expected ...any) EqualToMatcher

type Extractor

type Extractor func(T, any) (any, bool)

func NewChannelExtractor

func NewChannelExtractor(ve ValueExtractor, recurse bool) Extractor

func NewFuncExtractor

func NewFuncExtractor(ve ValueExtractor, recurse bool) Extractor

func NewPointerExtractor

func NewPointerExtractor(ve ValueExtractor, recurse bool) Extractor

type HasParent

type HasParent interface{ GetParent() T }

type Location

type Location struct {
	Function string
	File     string
	Line     int
	Source   string
}

type Matcher

type Matcher interface {
	Assert(t T, actuals ...any)
}

func BeBetween

func BeBetween(min, max any) Matcher

func BeEmpty

func BeEmpty() Matcher

func BeGreaterThan

func BeGreaterThan(min any) Matcher

func BeLessThan

func BeLessThan(max any) Matcher

func BeNil

func BeNil() Matcher

func Fail

func Fail(patterns ...string) Matcher

func Not

func Not(m Matcher) Matcher

func Say

func Say[Type string | *regexp.Regexp](expectation Type) Matcher

func Succeed

func Succeed() Matcher

type MatcherFunc

type MatcherFunc func(t T, actuals ...any)

func (MatcherFunc) Assert

func (f MatcherFunc) Assert(t T, actuals ...any)

type T

type T interface {
	Name() string
	Cleanup(f func())
	Fatalf(format string, args ...any)
	Failed() bool
	Log(args ...any)
	Logf(format string, args ...any)
}

type ValueExtractor

type ValueExtractor map[reflect.Kind]Extractor

func NewNumericValueExtractor

func NewNumericValueExtractor() ValueExtractor

func NewValueExtractor

func NewValueExtractor(defaultExtractor Extractor) ValueExtractor

func NewValueExtractorWithMap

func NewValueExtractorWithMap(defaultExtractor Extractor, extractors map[reflect.Kind]Extractor) ValueExtractor

func (ValueExtractor) ExtractValue

func (ve ValueExtractor) ExtractValue(t T, actual any) (any, bool)

func (ValueExtractor) MustExtractValue

func (ve ValueExtractor) MustExtractValue(t T, actual any) any

type VerifyOrEnsure added in v0.7.0

type VerifyOrEnsure interface {
	// EnsureThat adds a description to the upcoming assertion, which will be printed in case it fails.
	EnsureThat(string, ...any) Ensurer

	// Deprecated: Ensure is a synonym for EnsureThat.
	Ensure(string, ...any) Ensurer

	// VerifyThat starts an assertion without a description.
	VerifyThat(actuals ...any) Asserter

	// Deprecated: Verify is a synonym for VerifyThat.
	Verify(actuals ...any) Asserter
}

func With

func With(t T) VerifyOrEnsure

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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