Current section

Files

Jump to
commanded test support aggregate_case.ex
Raw

test/support/aggregate_case.ex

defmodule Commanded.AggregateCase do
@moduledoc """
This module defines the test case to be used by aggregate tests.
"""
use ExUnit.CaseTemplate
using aggregate: aggregate do
quote bind_quoted: [aggregate: aggregate] do
@aggregate_module aggregate
# Assert that the expected events are returned when the given commands have been executed
defp assert_events(commands, expected_events) do
assert_events([], commands, expected_events)
end
defp assert_events(initial_events, commands, expected_events) do
{_aggregate, events, error} = aggregate_run(initial_events, commands)
actual_events = List.wrap(events)
assert is_nil(error)
assert actual_events == expected_events
end
# Assert that the aggregate will have the expected_state after the given commands have been executed
defp assert_state(commands, expected_state) do
assert_state([], commands, expected_state)
end
defp assert_state(initial_events, commands, expected_state) do
{aggregate, events, error} = aggregate_run(initial_events, commands)
assert is_nil(error)
assert aggregate == expected_state
end
defp assert_error(commands, expected_error) do
assert_error([], commands, expected_error)
end
defp assert_error(initial_events, commands, expected_error) do
{_aggregate, _events, error} = aggregate_run(initial_events, commands)
assert error == expected_error
end
# Apply the given commands to the aggregate hydrated with the given initial_events
defp aggregate_run(initial_events, commands) do
%@aggregate_module{}
|> evolve(initial_events)
|> execute(commands)
end
# Execute one or more commands against an aggregate
defp execute(aggregate, commands) do
commands
|> List.wrap()
|> Enum.reduce({aggregate, [], nil}, fn
command, {aggregate, _events, nil} ->
case @aggregate_module.execute(aggregate, command) do
{:error, reason} = error -> {aggregate, nil, error}
events -> {evolve(aggregate, events), events, nil}
end
_command, {aggregate, _events, _error} = reply ->
reply
end)
end
# Apply the given events to the aggregate state
defp evolve(aggregate, events) do
events
|> List.wrap()
|> Enum.reduce(aggregate, &@aggregate_module.apply(&2, &1))
end
end
end
end