Skip to content

Latest commit

 

History

History
451 lines (344 loc) · 8.61 KB

MIGRATING-v0.11.0.md

File metadata and controls

451 lines (344 loc) · 8.61 KB

Migrating to version 0.11.0

Overview

This release includes extensive changes to the testing API. It formalizes the concepts of "actions" and "expectations" with the goal of a more consistent API and a greater level of extensibility.

Actions

An action is an operation performed within a test that causes the Dogma application being tested to do something. They are represented by the Action interface.

The following functions in the testkit package each return an Action:

  • ExecuteCommand()
  • RecordEvent()
  • AdvanceTime()
  • Call()

Prior to this release the Test type had methods with these names. These methods have been removed. Instead, the Test.Expect() method is used to perform a single action and fails the test unless it meets a specific expectation.

Actions can be performed without any expectations using Test.Prepare().

Expectations

An expectation is some criteria that an action is expected to meet. They are represented by the Expectation interface.

The following functions in the testkit package each return an Expectation:

  • ToExecuteCommand()
  • ToRecordEvent()
  • ToExecuteCommandOfType()
  • ToRecordEventOfType()
  • AllOf()
  • AnyOf()
  • NoneOf()
  • ToSatisfy()

Prior to this release expectations were called "assertions". These functions (some with slightly different names) were in the assert package, which has been removed.

Migrating existing tests

If you are migrating tests from testkit v0.10.0 or prior you will need to accomodate the changes listed in this section.

Example code is provided showing how each feature was used both before and after this release. Within these examples the test identifier refers to a testkit.Test variable. It is assumed that the testkit package has been "dot imported" meaning that any unqualified function call refers to a function in the testkit package.

Runner and New() have been removed

Prior to this release a Test was constructed by first constructing a Runner then calling its Begin() or BeginContext() method. The Runner type has been removed and its methods have been moved to functions in the testkit package.

BeforeAfter
test := New(app).Begin(t)
test := Begin(t, app)
test := New(app).BeginContext(ctx, t)
test := BeginContext(ctx, t, app)

Test.Prepare() now takes actions as parameters

Prior to this release Prepare() accepted dogma.Message parameters. It now requires Action values instead.

This change allows any action to be performed without an expectation. This is particularly useful with AdvanceTime() which was often used with the special assert.Nothing assertion to advance the test's virtual clock without making any real assertion.

BeforeAfter
test.Prepare(
    SomeCommand{ /* ... */ },
    SomeEvent{ /* ... */ },
)
test.Prepare(
    ExecuteCommand(SomeCommand{ /* ... */ }),
    RecordEvent(SomeEvent{ /* ... */ }),
)
test.AdvanceTime(
    ByDuration(10 * time.Second),
    assert.Nothing,
)
test.Prepare(
    AdvanceTime(ByDuration(10 * time.Second)),
)

Test.ExecuteCommand(), RecordEvent(), AdvanceTime() and Call() have been removed

These methods on Test have been replaced with functions of the same name, each of which returns an Action.

This change allows these actions to be performed without an expectation using Test.Prepare().

BeforeAfter
test.ExecuteCommand(
    SomeCommand{ /* ... */ },
    assert.EventRecorded(SomeEvent{ /* ... */ }),
)
test.Expect(
    ExecuteCommand(SomeCommand{ /* ... */ }),
    ToRecordEvent(SomeEvent{ /* ... */ }),
)
test.RecordEvent(
    SomeEvent{ /* ... */ },
    assert.CommandExecuted(SomeCommand{ /* ... */ }),
)
test.Expect(
    RecordEvent(SomeEvent{ /* ... */ }),
    ToExecuteCommand(SomeCommand{ /* ... */ }),
)
test.AdvanceTime(
    ByDuration(10 * time.Second),
    assert.EventRecorded(SomeEvent{ /* ... */ }),
)
test.Expect(
    AdvanceTime(ByDuration(10 * time.Second)),
    ToRecordEvent(SomeEvent{ /* ... */ }),
)
test.Call(
    func() error { return nil },
    assert.EventRecorded(SomeEvent{ /* ... */ }),
)
test.Expect(
    Call(func() { /* no error is returned ¹ */ }),
    ToRecordEvent(SomeEvent{ /* ... */ }),
)

The assert package has been removed

The commonly used assertions that were in the assert package have been reimplemented in testkit as expectations. Some of the function names have been changed.

The assert.Nothing assertion has been removed. It is no longer necessary as any action can be performed without an expectation using Test.Prepare().

BeforeAfter
assert.EventRecorded(SomeEvent{ /* ... */ })
ToRecordEvent(SomeEvent{ /* ... */ })
assert.EventTypeRecorded(SomeEvent{})
ToRecordEventOfType(SomeEvent{})
assert.CommandExecuted(SomeCommand{ /* ... */ })
ToExecuteCommand(SomeCommand{ /* ... */ })
assert.CommandTypeExecuted(SomeCommand{})
ToExecuteCommandOfType(SomeCommand{})
assert.AllOf(/* ... */)
AllOf(/* ... */)
assert.AnyOf(/* ... */)
AnyOf(/* ... */)
assert.NoneOf(/* ... */)
NoneOf(/* ... */)
assert.Should(
    "do something",
    func(s *assert.S) { /* ... */ },
)
ToSatisfy(
    "do something",
    func(t *SatisfyT) { /* ... */ },
)

Enabling and disabling message handlers

Within a Test both projection and integration message handler types are disabled by default. Prior to this release such handlers could be enabled using WithOperationOptions(...).

As of this release enabling or disabling handlers by type is discouraged ². Instead, individual handlers are enabled and disabled by name using the Test.EnableHandlers() and DisableHandlers() methods.

This change is made to accomodate future changes to the expectation and reporting systems that will analyse each handler's routing configuration to eliminate impossible expectations and provide more meaningful failure reports.

BeforeAfter
test := New().Begin(
    t,
    WithOperationOptions(
        engine.EnableProjections(true),
    ),
)
test := Begin(t).
    EnableHandlers("some-projection")

¹ The function passed to Call() no longer returns an error. Use the standard features of your testing framework to ensure no errors occur within the function.

² For the time being it is still possible to set engine operation options within a Test using WithUnsafeOperationOptions(). This approach provides no guarantees as to how these options will interact with the operation options that are set automatically by the Test.