Skip to content

[Recipe] Testing read model projectors #18

@slashdotdash

Description

@slashdotdash

How can I test a read model projector so that tests wait until events have been projected?

Using Elixir telemetry and the after_update/3 callback function

Commanded Ecto projections provides an after_update/3 callback function. This gets called after each event is projected. You can use the funtion to publish a notification whenever an event is projected, including the database changes.

Here’s an example using the Elixir/Erlang telemetry library.

In the projector:

def after_update(event, metadata, changes) do
  :telemetry.execute(
    [:projector],
    %{system_time: System.system_time()},
    %{event: event, metadata: metadata, changes: changes, projector: __MODULE__}
  )
end

In a test:

setup do
  reply_to = self()
  :ok =
    :telemetry.attach(
      "test-handler",
      [:projector],
      fn event, measurements, metadata, reply_to ->
        send(reply_to, {:telemetry, event, measurements, metadata})
      end,
      self()
    )
end

Usage in test to wait:

assert_receive {:telemetry, [:projector], _measurements, %{event: event, metadata: metadata, changes: changes}}

This approach will ensure the test blocks until the projector has done its work and then you can run either use the changes from the Ecto.Multi or run a query to verify the database changes. You can also use pattern matching on the event from the telemetry metadata to wait for a particular event type.

The performance impact at runtime is negligible if there are no handlers attached to a telemetry event.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions