Skip to content

When a Test Fails

A Stove test failure still has a stack trace, but the useful context is the evidence around it: console report, dashboard timeline, span tree, and optional MCP queries. Scroll to walk through what happens when a test goes red.

1. Assertion fails

You wrote a normal Stove test. shouldBePublished times out. The expected Kafka event never showed up.

The assertion failure anchors the report. Dashboard, tracing, and MCP add more evidence when enabled.

// OrderE2ETest.kt
test("order is published after POST /orders") {
  stove {
    http { post<OrderResponse>("/orders", ...) }
    kafka {
      shouldBePublished<OrderCreated> {
        actual.userId == userId
      }
    }
  }
}

FAILED after 10.0s
  org.opentest4j.AssertionFailedError:
  No matching OrderCreated event arrived
    within 10s on topic order.created.v1.

2. Console report fills in context

Stove's reporter prints the timeline that led up to the assertion: every HTTP call, every DB row, every published event, every WireMock stub hit. All serialized side-by-side with the failure.

No more guessing whether the bug was in your test, the app, or a downstream mock.

─── Stove Report ─────────────────────────────────
▶ http POST  /orders            201   42ms
▶ postgres INSERT INTO orders   1 row 6ms
▶ wiremock GET /inventory/x-1  200   3ms
✘ kafka shouldBePublished<OrderCreated>
        topic=order.created.v1   timeout=10s
        seen on bus: (none)
        most recent topics: order.failed.v1 (1)
────────────────────────────────────────────────────

3. Dashboard renders the full timeline

If the local dashboard is running, the same execution shows up as a clickable timeline at http://localhost:4040. System snapshots, message payloads, DB rows, all queryable.

Drill into the Kafka panel: the app published to order.failed.v1, not order.created.v1. Bug found.

┌─ Timeline ─────────────────────────────────────┐
│ 00:00.012  http     POST /orders         201  │
│ 00:00.054  postgres INSERT orders         1   │
│ 00:00.061  wiremock GET  /inventory/x-1   200 │
│ 00:00.080  kafka    published             !?  │
│            └─ topic: order.failed.v1        │
│               payload: {reason:"stock=0"}      │
│ 00:10.001  assertion timeout└────────────────────────────────────────────────┘

4. Trace tree shows the call chain inside the app

When tracing is enabled and the AUT is instrumented, the trace tree shows where the decision was made: controller, service, Kafka producer, and timing on each hop.

▾ POST /orders                       42ms
  ├─ OrderController.create        2ms
  ├─ ▾ OrderService.place           35ms
  │    ├─ InventoryClient.fetch    7ms
  │    ├─ ▾ StockGuard.check         1ms
  │    │    └─ returned: INSUFFICIENT
  │    └─ KafkaProducer.send          3ms
  │         topic = order.failed.v1
  └─ HTTP 201 returned

5. AI agent triages via MCP

The same data is exposed over a loopback MCP endpoint. An agent (Claude Code, Cursor, etc.) can fetch failures and traces directly. No shell-out, no log scraping, no token waste on noisy stdout.

It can return a focused diagnosis when the stored evidence is sufficient.

$ curl localhost:4040/mcp/tools/stove_failure_detail \
       -d '{"test_id":"OrderE2ETest#order-publish"}'

{
  failure: "kafka.shouldBePublished timeout",
  expected_topic: "order.created.v1",
  observed_topics: ["order.failed.v1"],
  span: "StockGuard.check returned INSUFFICIENT",
  suggestion: "InventoryClient returns stock=0. Verify
    test fixture seeded inventory before order"
}

How to get this loop in your project

This experience requires three things, all opt-in:

  • Tracing

    OpenTelemetry receiver plus JVM agent attachment for in-process JVM apps; non-JVM apps use their language SDK.

    Configure tracing · Try in wizard

  • Dashboard

    Local SQLite-backed UI streaming live test runs.

    Set up Dashboard

  • MCP

    Loopback agent endpoint exposed by stove-cli.

    Connect MCP