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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions