mesa

package module
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Dec 4, 2023 License: MIT Imports: 4 Imported by: 0

README

Mesa

Go golangci-lint Go Reference Maintainability

Mesa is a package for creating and running table driven tests in Go.

Install

go get github.com/a20r/mesa

Usage

Mesa provides two types of testing: method testing and function testing.

Testing methods

Method testing is used to test methods of a struct. To use Mesa for method testing, create a MethodMesa instance and define the following:

  • Init: an optional function called before running the test cases
  • NewInstance: a function that creates a new instance of the struct being tested
  • Target: the method being tested
  • Cases: an array of MethodCase instances that define the test cases
  • BeforeCall: an optional function to execute before calling the target method
  • Check: an optional function to check the output of the target method
  • Cleanup: an optional function to execute after the test case finishes
  • Teardown: an optional function called after all cases finish

Each MethodCase instance defines the following:

  • Name: the name of the test case
  • Fields or FieldsFn: the fields of the struct being tested
  • Input or InputFn: the input to the method being tested
  • Skip: an optional reason to skip the test case
  • [Override] BeforeCall: an optional function to execute before calling the target method
  • [Override] Check: an optional function to check the output of the target method
  • [Override] Cleanup: an optional function to execute after the test case finishes
Example
type MyStruct struct {
    Value int
}

func (s *MyStruct) Add(n int) {
    s.Value += n
}

func TestMyStruct_Add(t *testing.T) {
    m := mesa.MethodMesa[*MyStruct, int, int, mesa.Empty]{
        NewInstance: func(ctx *mesa.Ctx, value int) *MyStruct {
            return &MyStruct{Value: value}
        },
        Target: func(ctx *mesa.Ctx, inst *MyStruct, n int) mesa.Empty {
            inst.Add(n)
            return nil
        },
        Cases: []mesa.MethodCase[*MyStruct, int, int, mesa.Empty]{
            {
                Name:   "Add 1 to 0",
                Fields: 0,
                Input:  1,
                Check: func(ctx *mesa.Ctx, inst *MyStruct, in int, _ mesa.Empty) {
                    ctx.As.Equal(1, inst.Value)
                },
            },
            {
                Name:   "Add 2 to 1",
                Fields: 1,
                Input:  2,
                Check: func(ctx *mesa.Ctx, inst *MyStruct, in int, _ mesa.Empty) {
                    ctx.As.Equal(3, inst.Value)
                },
            },
        },
    }

    m.Run(t)
}

Testing functions

Function testing is used to test standalone functions. To use Mesa for function testing, create a FunctionMesa instance and define the following:

  • Init: an optional function called before running the test cases
  • Target: the function being tested
  • Cases: an array of FunctionCase instances that define the test cases
  • BeforeCall: an optional function to execute before calling the target function
  • Check: an optional function to check the output of the target function
  • Cleanup: an optional function to execute after the test case finishes
  • Teardown: an optional function called after all cases finish

Each FunctionCase instance defines the following:

  • Name: the name of the test case
  • Input or InputFn: the input to the function being tested
  • Skip: an optional reason to skip the test case
  • Check: an optional function to check the output of the target function
  • [Override] BeforeCall: an optional function to execute before calling the target function
  • [Override] Check: an optional function to check the output of the target function
  • [Override] Cleanup: an optional function to execute after the test case finishes
Example
func Add(a, b int) int {
    return a + b
}

func TestAdd(t *testing.T) {
    type input struct{ a, b int }

    m := mesa.FunctionMesa[input, int]{
        Target: func(ctx *mesa.Ctx, in input) int {
            return Add(in.a, in.b)
        },
        Cases: []mesa.FunctionCase[input, int]{
            {
                Name:  "Add 1 and 2",
                Input: input{a: 1, b: 2},
                Check: func(ctx *mesa.Ctx, in input, out int) {
                    ctx.As.Equal(3, out)
                },
            },
            {
                Name:  "Add 0 and 0",
                Input: input{a: 0, b: 0},
                Check: func(ctx *mesa.Ctx, in input, out int) {
                    ctx.As.Equal(0, out)
                },
            },
        },
    }

    m.Run(t)
}

Contributing

Contributions are welcome! Please see the contributing guidelines for more information.

License

Mesa is licensed under the MIT License.

Documentation

Overview

Mesa is a package for creating and running table driven tests

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MustAssert added in v0.8.0

func MustAssert[T any](ctx *Ctx, in any) T

MustAssert asserts the type of the given value and fails the test if the input cannot be asserted to the type.

func Run

func Run(t *testing.T, ms ...Mesa)

Run runs the provided test suites.

Types

type Ctx

type Ctx struct {
	context.Context

	As *assert.Assertions
	Re *require.Assertions
	// contains filtered or unexported fields
}

Ctx represents the test context containing the testing.T instance and assertion objects for convenience.

func (*Ctx) B added in v0.7.0

func (c *Ctx) B() *testing.B

B returns the underlying testing.B instance if it is being used for benchmarking. The benchmark will fail if the Ctx is being used for tests.

func (*Ctx) GetValue added in v0.10.0

func (c *Ctx) GetValue(name string) any

GetValue gets a value with the given name from the context

func (*Ctx) ReportMetric added in v0.10.0

func (c *Ctx) ReportMetric(value float64, name string)

ReportMetric adds the benchmarking metric with the given name to the context. The metrics are divided by the number of calls (b.N) once the benchmark is complete. It will panic if the context is being used for tests

func (*Ctx) SetValue added in v0.10.0

func (c *Ctx) SetValue(name string, val any)

SetValue sets a value with the given name in the context

func (*Ctx) T

func (c *Ctx) T() *testing.T

T returns the underlying testing.T instance if it is being used tests. The test will fail if the Ctx is being used for benchmarking.

type Empty added in v0.2.1

type Empty any

Empty is a type used when testing structs and functions without fields or return values

type ErrorPair added in v0.5.0

type ErrorPair[T any] struct {
	Value T
	Err   error
}

ErrorPair is a convenience type used to wrap function outputs that return a value and an error

func NewErrorPair added in v0.5.1

func NewErrorPair[T any](value T, err error) ErrorPair[T]

NewErrorPair creates a new error pair with the provided value and error

type FunctionCase

type FunctionCase[InputType, OutputType any] struct {
	// [Required] Name of the test case.
	Name string

	// [Optional] Input data for the test case. InputFn takes priority over Input. The Input field can be empty if the
	// target function does not take any arguments.
	Input InputType

	// [Optional] InputFn returns the input struct used for this case. It takes priority over the Input field. This can
	// be empty if the target function does not take any arguments.
	InputFn func(ctx *Ctx) InputType

	// [Optional] Reason to skip the test case. The test is only skipped if this field is not empty
	Skip string

	// [Optional] Function to execute before calling the target function. It will be called instead of the BeforeCall
	// function in the FunctionMesa if provided.
	BeforeCall func(ctx *Ctx, in InputType)

	// [Optional] Function to check the output of the target function. It will be called instead of the Check
	// function in the FunctionMesa if provided.
	Check func(ctx *Ctx, in InputType, out OutputType)

	// [Optional] Cleanup function to execute after the test case finishes. It will be called instead of the Cleanup
	// function in the FunctionMesa if provided.
	Cleanup func(ctx *Ctx)
}

FunctionCase represents a test case with its associated properties.

type FunctionMesa

type FunctionMesa[InputType, OutputType any] struct {
	// [Optional] Function to initialize anything before running the test cases
	Init func(ctx *Ctx)

	// [Required] Target function under test.
	Target func(ctx *Ctx, in InputType) OutputType

	// [Required] List of test cases.
	Cases []FunctionCase[InputType, OutputType]

	// [Optional] Function to execute before calling the target function. This is called when no BeforeCall function
	// is provided by the the case itself.
	BeforeCall func(ctx *Ctx, in InputType)

	// [Optional] Function to check the output of the target function. This is called when no Check function
	// is provided by the the case itself.
	Check func(ctx *Ctx, in InputType, out OutputType)

	// [Optional] Cleanup function to execute after the test case finishes. This is called when no Cleanup function
	// is provided by the the case itself.
	Cleanup func(ctx *Ctx)

	// [Optional] Teardown function is called after all cases finish
	Teardown func(ctx *Ctx)
}

FunctionMesa represents a collection of test cases that execute the target function under each test case.

Example
package main

import (
	"testing"

	"github.com/a20r/mesa"
)

func Add(a, b int) int {
	return a + b
}

func main() {
	type input struct{ a, b int }

	m := mesa.FunctionMesa[input, int]{
		Target: func(ctx *mesa.Ctx, in input) int {
			return Add(in.a, in.b)
		},
		Cases: []mesa.FunctionCase[input, int]{
			{
				Name:  "Add 1 and 2",
				Input: input{a: 1, b: 2},
				Check: func(ctx *mesa.Ctx, in input, out int) {
					ctx.As.Equal(3, out)
				},
			},
			{
				Name:  "Add 0 and 0",
				Input: input{a: 0, b: 0},
				Check: func(ctx *mesa.Ctx, in input, out int) {
					ctx.As.Equal(0, out)
				},
			},
		},
	}

	var t *testing.T
	m.Run(t)
}
Output:

func (FunctionMesa[I, O]) Run

func (m FunctionMesa[I, O]) Run(t *testing.T)

Run executes all the test cases in the FunctionMesa instance.

type Mesa

type Mesa interface {
	// Run runs the test suite.
	Run(t *testing.T)
}

Mesa is an interface that defines a method to run a test suite.

type MethodBenchmarkCase added in v0.6.0

type MethodBenchmarkCase[InstanceType, FieldsType, InputType, OutputType any] struct {
	// [Required] Name of the benchmark case.
	Name string

	// [Optional] Fields associated with the instance. FieldsFn takes priority over Fields. If fields are not needed
	// to instantiate a the benchmark instance, no fields need to be provided.
	Fields FieldsType

	// [Optional] FieldsFn returns the fields used for this case. FieldsFn takes priority over Fields. If fields are
	// not needed to instantiate a the benchmark instance, no fields need to be provided.
	FieldsFn func(ctx *Ctx) FieldsType

	// [Optional] Input data for the benchmark case. InputFn takes priority over Input. The Input field can be empty if the
	// target function does not take any arguments.
	Input InputType

	// [Optional] InputFn returns the input struct used for this case. It takes priority over the Input field. This can
	// be empty if the target function does not take any arguments.
	InputFn func(ctx *Ctx, inst InstanceType) InputType

	// [Optional] Function to check the output of the target function. It will be called instead of the Check function
	// in the MethodMesa if provided.
	Check func(ctx *Ctx, inst InstanceType, in InputType, out OutputType)

	// [Optional] Reason to skip the benchmark case. The benchmark is only skipped if this field is not empty
	Skip string

	// [Optional] Function to execute before calling the target function. It will be called instead of the BeforeCall
	// function in the MethodMesa if provided.
	BeforeCall func(ctx *Ctx, inst InstanceType, in InputType)

	// [Optional] Cleanup function to execute after the benchmark case finishes. It will be called instead of the Cleanup
	// function in the MethodMesa if provided.
	Cleanup func(ctx *Ctx, inst InstanceType)
}

MethodBenchmarkCase represents a benchmark case with its associated properties.

type MethodBenchmarkMesa added in v0.6.0

type MethodBenchmarkMesa[InstanceType, FieldsType, InputType, OutputType any] struct {
	// [Optional] Function to initialize anything before running the test cases
	Init func(ctx *Ctx)

	// [Required] Function to create a new instance.
	NewInstance func(ctx *Ctx, fields FieldsType) InstanceType

	// [Required] Target function under test.
	Target func(ctx *Ctx, inst InstanceType, in InputType) OutputType

	// [Required] List of test cases.
	Cases []MethodBenchmarkCase[InstanceType, FieldsType, InputType, OutputType]

	// [Optional] Function to check the output of the target function. It will be called instead of the Check function
	// in the MethodMesa if provided.
	Check func(ctx *Ctx, inst InstanceType, in InputType, out OutputType)

	// [Optional] Function to execute before calling the target function. This is called when no BeforeCall function
	// is provided by the the case itself.
	BeforeCall func(ctx *Ctx, inst InstanceType, in InputType)

	// [Optional] Cleanup function to execute after the test case finishes. This is called when no Cleanup function
	// is provided by the the case itself.
	Cleanup func(ctx *Ctx, inst InstanceType)

	// [Optional] Teardown function is called after all cases finish
	Teardown func(ctx *Ctx)
}

MethodBenchmarkMesa represents a collection of test cases and the functions to create instances and execute the target function under test.

func (MethodBenchmarkMesa[Inst, F, I, O]) Run added in v0.6.0

func (m MethodBenchmarkMesa[Inst, F, I, O]) Run(b *testing.B)

Run executes all the benchmark cases in the Mesa instance.

func (MethodBenchmarkMesa[Inst, F, I, O]) WithCases added in v0.9.0

func (m MethodBenchmarkMesa[Inst, F, I, O]) WithCases(
	cases []MethodBenchmarkCase[Inst, F, I, O],
) MethodBenchmarkMesa[Inst, F, I, O]

WithCases returns a new instance using the provided cases.

type MethodCase

type MethodCase[InstanceType, FieldsType, InputType, OutputType any] struct {
	// [Required] Name of the test case.
	Name string

	// [Optional] Fields associated with the instance. FieldsFn takes priority over Fields. If fields are not needed
	// to instantiate a the test instance, no fields need to be provided.
	Fields FieldsType

	// [Optional] FieldsFn returns the fields used for this case. FieldsFn takes priority over Fields. If fields are
	// not needed to instantiate a the test instance, no fields need to be provided.
	FieldsFn func(ctx *Ctx) FieldsType

	// [Optional] Input data for the test case. InputFn takes priority over Input. The Input field can be empty if the
	// target function does not take any arguments.
	Input InputType

	// [Optional] InputFn returns the input struct used for this case. It takes priority over the Input field. This can
	// be empty if the target function does not take any arguments.
	InputFn func(ctx *Ctx, inst InstanceType) InputType

	// [Optional] Reason to skip the test case. The test is only skipped if this field is not empty
	Skip string

	// [Optional] Function to execute before calling the target function. It will be called instead of the BeforeCall
	// function in the MethodMesa if provided.
	BeforeCall func(ctx *Ctx, inst InstanceType, in InputType)

	// [Optional] Function to check the output of the target function. It will be called instead of the Check function
	// in the MethodMesa if provided.
	Check func(ctx *Ctx, inst InstanceType, in InputType, out OutputType)

	// [Optional] Cleanup function to execute after the test case finishes. It will be called instead of the Cleanup
	// function in the MethodMesa if provided.
	Cleanup func(ctx *Ctx, inst InstanceType)
}

MethodCase represents a test case with its associated properties.

type MethodMesa

type MethodMesa[InstanceType, FieldsType, InputType, OutputType any] struct {
	// [Optional] Function to initialize anything before running the test cases
	Init func(ctx *Ctx)

	// [Required] Function to create a new instance.
	NewInstance func(ctx *Ctx, fields FieldsType) InstanceType

	// [Required] Target function under test.
	Target func(ctx *Ctx, inst InstanceType, in InputType) OutputType

	// [Required] List of test cases.
	Cases []MethodCase[InstanceType, FieldsType, InputType, OutputType]

	// [Optional] Function to execute before calling the target function. This is called when no BeforeCall function
	// is provided by the the case itself.
	BeforeCall func(ctx *Ctx, inst InstanceType, in InputType)

	// [Optional] Function to check the output of the target function. This is called when no Check function
	// is provided by the the case itself.
	Check func(ctx *Ctx, inst InstanceType, in InputType, out OutputType)

	// [Optional] Cleanup function to execute after the test case finishes. This is called when no Cleanup function
	// is provided by the the case itself.
	Cleanup func(ctx *Ctx, inst InstanceType)

	// [Optional] Teardown function is called after all cases finish
	Teardown func(ctx *Ctx)
}

MethodMesa represents a collection of test cases and the functions to create instances and execute the target function under test.

Example
package main

import (
	"testing"

	"github.com/a20r/mesa"
)

type MyStruct struct {
	Value int
}

func (s *MyStruct) Add(n int) {
	s.Value += n
}

func main() {
	m := mesa.MethodMesa[*MyStruct, int, int, mesa.Empty]{
		NewInstance: func(ctx *mesa.Ctx, value int) *MyStruct {
			return &MyStruct{Value: value}
		},
		Target: func(ctx *mesa.Ctx, inst *MyStruct, n int) mesa.Empty {
			inst.Add(n)
			return nil
		},
		Cases: []mesa.MethodCase[*MyStruct, int, int, mesa.Empty]{
			{
				Name:   "Add 1 to 0",
				Fields: 0,
				Input:  1,
				Check: func(ctx *mesa.Ctx, inst *MyStruct, in int, _ mesa.Empty) {
					ctx.As.Equal(1, inst.Value)
				},
			},
			{
				Name:   "Add 2 to 1",
				Fields: 1,
				Input:  2,
				Check: func(ctx *mesa.Ctx, inst *MyStruct, in int, _ mesa.Empty) {
					ctx.As.Equal(3, inst.Value)
				},
			},
		},
	}

	var t *testing.T
	m.Run(t)
}
Output:

func (MethodMesa[Inst, F, I, O]) Run

func (m MethodMesa[Inst, F, I, O]) Run(t *testing.T)

Run executes all the test cases in the Mesa instance.

Jump to

Keyboard shortcuts

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