Packages

Process Intelligence and Conformance Checking for ExUnit (pm4pytest for Elixir)

Current section

Files

Jump to
pm4exunit docs tutorials first-conformance-test.md
Raw

docs/tutorials/first-conformance-test.md

# Write your first conformance test

In this tutorial you will add pm4exunit to a project, record events in a test, and watch a
conformance assertion pass and then fail. It takes about ten minutes.

## 1. Add the dependency

In `mix.exs`:

```elixir
{:pm4exunit, "~> 26.11", only: :test}
```

Run `mix deps.get`.

## 2. Write a passing test

Create `test/order_saga_test.exs`:

```elixir
defmodule OrderSagaTest do
  use ExUnit.Case
  use Pm4ExUnit

  test "order saga follows the model", %{pm4_session: session} do
    emit_event(session, "e1", :order_created)
    emit_event(session, "e2", :payment_processed)
    emit_event(session, "e3", :order_fulfilled)

    assert_conformance(session, [[:order_created, :payment_processed, :order_fulfilled]])
  end
end
```

`use Pm4ExUnit` starts a session for each test and passes it in the test context as
`:pm4_session`. The list of lists is the model: each inner list is one allowed path.

Run `mix test`. The test passes.

## 3. Break it

Delete the `:payment_processed` line and run `mix test` again. The assertion fails with a
message like:

```text
Process Conformance Assertion Failed!
Minimum Fitness Required: 1.0
Observed Fitness: 0.5833
Violations:
  * Conformance fitness 0.5833 is below required minimum 1.0.
  * Trace missed 1 mandatory transition(s) in path: ["order_created", "payment_processed", "order_fulfilled"].
  * Trace ended with 1 unconsumed token(s) (premature termination or superfluous transitions).
Diagnostics:
  Trace: ["order_created", "order_fulfilled"]
  Missing Tokens: 1
  Remaining Tokens: 1
```

The expected path is printed in the violations; compare it with the trace under Diagnostics to
see which step is missing.

## 4. Add a latency limit

Add a second test:

```elixir
test "fulfilment is fast enough", %{pm4_session: session} do
  t0 = ~U[2026-11-12 10:00:00Z]

  emit_event(session, "e1", :order_created, timestamp: t0)
  emit_event(session, "e2", :order_fulfilled, timestamp: DateTime.add(t0, 2, :second))

  assert_sla(session, :order_created, :order_fulfilled, max_seconds: 5.0)
end
```

Change `2` to `9` and it fails with `SLA violated`.

## Next

- Several valid paths: [model-multiple-paths](../how-to/model-multiple-paths.md)
- What the fitness number means: [token-based replay](../explanation/token-based-replay.md)