gtest

package
v0.4.6 Latest Latest
Warning

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

Go to latest
Published: Nov 28, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

README

Testing Utilities

This is an experimental package for testing utilities. The API may change at any time.

The gtest package will provide a suite of tools for easily testing event-sourcing patterns. Currently, you can:

  • Test aggregate constructors.
  • Ensure aggregates produce the expected events.
  • Check for unexpected events from aggregates.

Usage

Consider an aggregate User:

package auth

import (
	"github.com/google/uuid"
	"github.com/modernice/goes/aggregate"
	"github.com/modernice/goes/event"
)

type User struct {
	*aggregate.Base

	Username string
	Age      int
}

func NewUser(id uuid.UUID) *User {
	user := &User{Base: aggregate.New("auth.user", id)}

	event.ApplyWith(user, user.created, "auth.user.created")

	return user
}

type UserCreation struct {
	Username string
	Age      int
}

func (u *User) Create(username string, age int) error {
	if username == "" {
		return fmt.Errorf("username cannot be empty")
	}

	if age < 0 {
		return fmt.Errorf("age cannot be negative")
	}

	aggregate.Next(u, "auth.user.created", UserCreation{
		Username: username,
		Age:      age,
	})

	return nil
}

func (u *User) created(e event.Of[UserCreation]) {
	u.Username = e.Data().Username
	u.Age = e.Data().Age
}

Using gtest, you can efficiently test this aggregate.

Testing Constructors

To ensure the NewUser constructor returns a valid User with the correct AggregateID:

func TestNewUser(t *testing.T) {
	gtest.Constructor(auth.NewUser).Run(t)
}
Testing Aggregate Transitions

To ensure the User aggregate correctly transitions to the auth.user.created event with expected data:

func TestUser_Create(t *testing.T) {
	u := auth.NewUser(uuid.New())

	if err := u.Create("Alice", 25); err != nil {
		t.Errorf("Create failed: %v", err)
	}

	gtest.Transition(
		"auth.user.created",
		UserCreation{Username: "Alice", Age: 25},
	).Run(t, u)

	if u.Username != "Alice" {
		t.Errorf("expected Username to be %q; got %q", "Alice", u.Username)
	}

	if u.Age != 25 {
		t.Errorf("expected Age to be %d; got %d", 25, u.Age)
	}
}
Testing Signals (events without data)

To ensure the User aggregate correctly transitions to the auth.user.deleted event:

func TestUser_Delete(t *testing.T) {
	u := auth.NewUser(uuid.New())

	if err := u.Delete(); err != nil {
		t.Errorf("Delete failed: %v", err)
	}

	gtest.Signal("auth.user.deleted").Run(t, u)
}
Testing Non-Transitions

To ensure a specific event (e.g., auth.user.created) is not emitted by the User aggregate:

func TestUser_Create_negativeAge(t *testing.T) {
	u := auth.NewUser(uuid.New())

	if err := u.Create("Alice", -3); err == nil {
		t.Errorf("Create should fail with negative age")
	}

	gtest.NonTransition("auth.user.created").Run(t, u)
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Comparable added in v0.4.3

type Comparable[T any] interface {
	Equal(T) bool
}

Comparable is an interface that provides a method for comparing two instances of the same type. The Equal method should return true if the two instances are considered equivalent, and false otherwise.

type ConstructorTest

type ConstructorTest[A aggregate.Aggregate] struct {
	Constructor func(uuid.UUID) A
	OnCreated   func(A) error
}

ConstructorTest is a test for aggregate constructors. It checks if the constructor properly sets the AggregateID and calls the OnCreated hook, if provided, with the created aggregate.

func Constructor

func Constructor[A aggregate.Aggregate](constructor func(uuid.UUID) A, opts ...ConstructorTestOption[A]) *ConstructorTest[A]

Constructor creates a new ConstructorTest with the specified constructor function and optional test options. It returns a pointer to the created ConstructorTest.

func (*ConstructorTest[A]) Run

func (test *ConstructorTest[A]) Run(t *testing.T)

Run executes the ConstructorTest, ensuring that the constructed aggregate has the correct UUID and, if provided, calls the OnCreated hook without errors. If any of these checks fail, an error is reported to the given testing.T.

type ConstructorTestOption

type ConstructorTestOption[A aggregate.Aggregate] func(*ConstructorTest[A])

ConstructorTestOption is a function that modifies a ConstructorTest for an Aggregate. It is used to customize the behavior of a ConstructorTest, such as providing a custom OnCreated hook function.

func Created

func Created[A aggregate.Aggregate](fn func(A) error) ConstructorTestOption[A]

Created configures a ConstructorTest with a custom function to be called when an Aggregate is created, allowing for additional validation or setup steps. The provided function takes the created Aggregate as its argument and returns an error if any issues are encountered during execution.

type NonTransition

type NonTransition string

NonTransition represents an event that the aggregate should not transition to. It's used in testing to ensure that a specific event does not occur during the test run for a given aggregate.

func (NonTransition) Run

func (event NonTransition) Run(t *testing.T, a aggregate.Aggregate)

Run checks if the given aggregate a does not transition to the event specified by the NonTransition type. If it does, an error is reported with testing.T.

type TransitionTest

type TransitionTest[EventData any] struct {
	Event string
	Data  EventData
	// contains filtered or unexported fields
}

TransitionTest represents a test that checks whether an aggregate transitions to a specific event with the specified data. It can be used to ensure that an aggregate properly handles its internal state changes and produces the correct events with the expected data.

func Signal

func Signal(event string, opts ...TransitionTestOption) *TransitionTest[any]

Signal returns a new TransitionTest with the specified event name and no event data. It is used to test aggregate transitions for events without data.

func Transition

func Transition[EventData comparable](event string, data EventData, opts ...TransitionTestOption) *TransitionTest[EventData]

Transition creates a new TransitionTest with the specified event name and data. It can be used to test if an aggregate transitions to the specified event with the provided data when running the Run method on a *testing.T instance.

func TransitionWithComparer added in v0.4.5

func TransitionWithComparer[EventData any](event string, data EventData, compare func(EventData, EventData) bool, opts ...TransitionTestOption) *TransitionTest[EventData]

TransitionWithComparer creates a new TransitionTest with the specified event name and data, using a custom comparison function to compare event data. It is used for testing if an aggregate transitions to the specified event with the provided data when running the Run method on a *testing.T instance. TransitionTestOptions can be provided to customize the behavior of the TransitionTest.

func TransitionWithEqual added in v0.4.3

func TransitionWithEqual[EventData Comparable[EventData]](event string, data EventData, opts ...TransitionTestOption) *TransitionTest[EventData]

TransitionWithEqual creates a new TransitionTest with the specified event name and data, using the Equal method of the Comparable interface to compare event data. It is used for testing if an aggregate transitions to the specified event with the provided data, when running the Run method on a *testing.T instance. The comparison of event data is based on the Equal method, which should be implemented by the provided EventData type. TransitionTestOptions can be provided to customize the behavior of the TransitionTest.

func (*TransitionTest[EventData]) Run

func (test *TransitionTest[EventData]) Run(t *testing.T, a aggregate.Aggregate)

Run tests whether an aggregate transitions to the specified event with the expected data. It reports an error if the aggregate does not transition to the specified event, or if the event data does not match the expected data.

type TransitionTestOption

type TransitionTestOption func(*transitionTestConfig)

TransitionTestOption is a function that modifies the behavior of a TransitionTest, such as configuring the number of times an event should be matched. It takes a transitionTestConfig struct and modifies its properties based on the desired configuration.

func Once

func Once() TransitionTestOption

Once returns a TransitionTestOption that configures a TransitionTest to expect the specified event and data exactly once.

func Times

func Times(times uint) TransitionTestOption

Times is a TransitionTestOption that configures the number of times an event should match the expected data in a TransitionTest. It takes an unsigned integer argument representing the number of matches expected.

Jump to

Keyboard shortcuts

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