Skip to content

Systems

Stove is pluggable. Each dependency, test-side client, mock, and observability surface is a separate system module. AUT runners are registered separately to start or target the application under test. Add only what your tests need. Default mode uses Testcontainers; switch to Provided Instances when the infrastructure already exists or Docker is unavailable.

Most teams start small Two to four systems usually gets a useful first suite: one driver such as HTTP or gRPC, and the stateful systems the use case touches. Then register one AUT runner. Add tracing and dashboard when failure diagnosis needs more than console output.

Pick a starting set

You're testing Add these
HTTP API + SQL stove-http + stove-postgres (or -mysql)
Event-driven service stove-kafka + your DB + stove-tracing
Service calling external API stove-http + stove-wiremock
gRPC service stove-grpc + stove-grpc-mock
Stateful service with caching your DB + stove-redis
Already-running service (any language) stove-http + any provided dependencies + providedApplication()

Wizard composes this for you: open with Postgres + Kafka + WireMock.

Catalog

🗄 Databases

PostgreSQLSQL

Relational. Migrations, transactions, full SQL DSL.

MySQLSQL

Relational alternative for MySQL-targeted apps.

MSSQLSQL

Microsoft SQL Server with T-SQL support.

MongoDBDocument

JSON document storage with aggregation.

CouchbaseDocument

N1QL queries, KV ops, FTS.

CassandraWide-column

Time-series, IoT, large-scale writes. CQL DSL.

RedisKV

In-memory cache, sessions, pub/sub.

ElasticsearchSearch

Full-text search and analytics.

📨 Messaging

KafkaPub/Sub

Publish/consume assertions, interceptor-based capture, time-bounded waits.

🌐 Network

HTTP ClientDrive

Drive your app's HTTP API and assert decoded responses.

gRPC ClientDrive

Call your gRPC services with Wire and grpc-kotlin clients.

🪞 Mocks

WireMockHTTP

Mock third-party HTTP services at the network edge.

gRPC MockgRPC

Mock external gRPC services.

📈 Observability

ReportingConsole

Console and JSON failure reports with timelines and system snapshots.

TracingOTel

OpenTelemetry spans and validation DSL for application call chains.

DashboardLocal UI

SQLite-backed local UI for timelines, traces, and snapshots.

MCPAgent API

Loopback read-only API for AI agents to triage failures.

🔌 Integration

BridgeDI access

Reach into supported JVM DI containers for setup and verification.

Provided InstancesNo Docker

Connect to existing infrastructure instead of Testcontainers.

Provided ApplicationBlack-box

Test an already-running app as a black-box target.

Multiple SystemsKeyed

Multiple named instances of the same system type (microservices).

Container AUTPolyglot

Run any Docker image as the app under test (Go, Python, Node...).

Every system shares the same shape

Once you configure one system, the lifecycle is the same for the rest.

componentName 1 { ComponentSystemOptions( container = ContainerOptions( 2 registry = "docker.io", image = "component-image", tag = "1.2.3" ), configureExposedConfiguration = { cfg -> 3 listOf( "app.component.host=${cfg.host}", "app.component.port=${cfg.port}" ) }, cleanup = { ops -> ops.execute("...") } 4 ) }
1DSL block registers the system before the suite starts.
2Runtime options pin a container image and tag, or switch to .provided(...) for existing infrastructure.
3Exposed config converts runtime values (host, port, URL, credentials) into properties before the app boots.
4Cleanup removes test data when Stove stops. Essential for shared infrastructure.

Container mode vs Provided Instances

Container mode (default)

Stove starts Testcontainers. Best for local development and CI runners with Docker.

kafka {
  KafkaSystemOptions(
    container = KafkaContainerOptions(tag = "latest"),
    configureExposedConfiguration = { cfg -> listOf(...) }
  )
}

Provided instance

Connect to existing infrastructure. Best when Docker isn't available or CI already runs shared Kafka/Postgres.

kafka {
  KafkaSystemOptions.provided(
    bootstrapServers = "localhost:9092",
    configureExposedConfiguration = { cfg -> listOf(...) }
  )
}

See Provided Instances for prefixing strategies that prevent collisions on shared infra.

Migrations and cleanup

Databases and other stateful systems support migrations and per-system cleanup hooks. Migrations run during suite startup before the application receives dependency configuration; cleanup runs when Stove stops at suite teardown.

class CreateTablesMigration : DatabaseMigration<PostgresSqlMigrationContext> {
  override val order: Int = 1
  override suspend fun execute(connection: PostgresSqlMigrationContext) {
    connection.operations.execute("CREATE TABLE orders ...")
  }
}

postgresql {
  PostgresqlOptions(
    cleanup = { ops -> ops.execute("DELETE FROM orders WHERE test = true") },
    configureExposedConfiguration = { cfg -> listOf(...) }
  ).migrations { register<CreateTablesMigration>() }
}

Full-stack test, all systems at once

test("order flows across HTTP, DB, Kafka, ES, Redis") {
  stove {
    val orderId = UUID.randomUUID().toString()

    wiremock {
      mockPost("/payments", 200, PaymentResult(success = true).some())
    }

    http {
      postAndExpectBody<OrderResponse>(
        "/orders", body = CreateOrderRequest(orderId).some()
      ) { it.status shouldBe 201 }
    }

    couchbase {
      shouldGet<Order>("orders", orderId) { it.status shouldBe "CREATED" }
    }

    kafka {
      shouldBePublished<OrderCreatedEvent> { actual.orderId == orderId }
    }

    elasticsearch {
      shouldGet<Order>(index = "orders", key = orderId) {
        it.status shouldBe "CREATED"
      }
    }

    redis {
      client().connect().sync().get("order:$orderId") shouldNotBe null
    }
  }
}

For a full annotated walkthrough of this pattern, see the order placement recipe.

Where to next