Outboxer.Testing (Outboxer v0.1.0)

Copy Markdown View Source

Helpers for testing code that publishes to an outbox.

Start Outboxer with testing: :manual in your test environment. No workers run, so nothing is relayed behind your back and the Ecto SQL sandbox needs no special arrangement: Outboxer.publish/2 writes through the test's own connection and the rows roll back with the test.

# config/test.exs
config :my_app, :outboxer, testing: :manual

# application.ex
{Outboxer, [repo: MyApp.Repo, outboxes: [...]] ++ Application.get_env(:my_app, :outboxer, [])}

Then, in a test:

import Outboxer.Testing

test "placing an order publishes an event" do
  {:ok, order} = Orders.place(params)

  envelope = assert_published(:orders, MyApp.Events.OrderPlaced)
  assert JSON.decode!(envelope.payload)["order_id"] == order.id
end

To exercise the relay too, call drain/2, which delivers synchronously in the test process.

Summary

Functions

Asserts that a pending message matching matcher exists and returns the first one.

Delivers everything currently deliverable in an outbox, synchronously, in the calling process, through the configured relay.

Returns the pending messages of an outbox, oldest first.

Asserts that no pending message matches matcher. See assert_published/3.

Functions

assert_published(outbox, matcher, opts \\ [])

@spec assert_published(
  atom(),
  module() | String.t() | (Outboxer.Envelope.t() -> boolean()),
  keyword()
) ::
  Outboxer.Envelope.t()

Asserts that a pending message matching matcher exists and returns the first one.

matcher is a message module (matches on its type), a type string, or a function taking the envelope and returning a boolean.

assert_published(:orders, MyApp.Events.OrderPlaced)
assert_published(:orders, "order.placed")
assert_published(:orders, &(&1.group_key == "order:1"))

drain(outbox, opts \\ [])

@spec drain(atom(), keyword()) :: %{
  delivered: non_neg_integer(),
  failed: non_neg_integer(),
  dead: non_neg_integer()
}

Delivers everything currently deliverable in an outbox, synchronously, in the calling process, through the configured relay.

Returns %{delivered: n, failed: n, dead: n}. It stops as soon as a pass delivers nothing, so a message that keeps failing cannot make it loop.

Options

  • :name - the Outboxer instance, default Outboxer.

published(outbox, opts \\ [])

@spec published(atom(), keyword()) :: [Outboxer.Envelope.t()]

Returns the pending messages of an outbox, oldest first.

Options

  • :name - the Outboxer instance, default Outboxer.
  • :limit - maximum number of messages, default 100.

refute_published(outbox, matcher, opts \\ [])

@spec refute_published(
  atom(),
  module() | String.t() | (Outboxer.Envelope.t() -> boolean()),
  keyword()
) ::
  :ok

Asserts that no pending message matches matcher. See assert_published/3.