Multiple Systems (Keyed)¶
Default: one instance per system type. Need more? Register multiple instances of the same type with typed keys. This is useful for microservice integration, multiple databases, multi-cluster Kafka, and cross-service verification.
In 30 seconds
Define keys as Kotlin objects implementing SystemKey. Pass the key as the first argument to any system DSL: postgresql(AppDb) { }, kafka(MainCluster) { }, httpClient(PaymentService) { }. Use the same key inside stove { } to target that instance.
Define keys¶
Keys are Kotlin singletons implementing SystemKey. They show up in reports and traces, so name them after the role the instance plays.
object AppDb : SystemKey
object AnalyticsDb : SystemKey
object MainCluster : SystemKey
object AuditCluster : SystemKey
object PaymentService : SystemKey
object InventoryService : SystemKey
Why objects, not strings?
Typed keys catch typos at compile time and let IDEs autocomplete usages. Strings would silently bind to "new" instances if misspelled.
Register keyed instances¶
Pass the key as the first arg. Options and validation APIs match the single-instance API. Default and keyed instances can coexist.
Stove().with {
// Default, unkeyed Postgres (optional)
postgresql {
PostgresqlOptions(/* ... */)
}
// Keyed instances: separate containers, ports, and state
postgresql(AppDb) {
PostgresqlOptions(
databaseName = "app",
configureExposedConfiguration = { cfg ->
listOf("app.datasource.url=${cfg.jdbcUrl}")
}
)
}
postgresql(AnalyticsDb) {
PostgresqlOptions(
databaseName = "analytics",
configureExposedConfiguration = { cfg ->
listOf("analytics.datasource.url=${cfg.jdbcUrl}")
}
)
}
httpClient(PaymentService) {
HttpClientSystemOptions(baseUrl = "https://pay.internal")
}
httpClient(InventoryService) {
HttpClientSystemOptions(baseUrl = "https://inv.internal")
}
springBoot(runner = { params -> com.app.run(params) })
}.run()
Use keys in tests¶
Use the same validation DSL and pass the key to target the right instance:
stove {
postgresql(AppDb) {
shouldExecute("INSERT INTO users(id) VALUES ('u1')")
}
postgresql(AnalyticsDb) {
shouldQuery<EventRow>("SELECT * FROM events") { it shouldHaveSize 0 }
}
httpClient(PaymentService) {
get<PaymentResponse>("/health") { it.status shouldBe "OK" }
}
httpClient(InventoryService) {
post<InventoryResponse>("/reserve", body) { it.status shouldBe 200 }
}
}
Supported systems¶
The built-in systems below support keyed registration:
postgresql · mysql · mssql · mongodb · couchbase · cassandra · redis · elasticsearch · kafka · httpClient · grpc · grpcMock · wiremock
Combine with remote services¶
For microservice integration tests where your AUT runs locally but dependencies are already deployed, key the remote endpoints:
Stove().with {
// Your service runs locally
springBoot(runner = { params -> com.app.run(params) })
// Upstream / downstream services already running
httpClient(PaymentService) {
HttpClientSystemOptions(baseUrl = "https://pay.staging")
}
httpClient(InventoryService) {
HttpClientSystemOptions(baseUrl = "https://inv.staging")
}
}.run()
Reporting¶
Keyed instances appear in failure reports with their key name, e.g. kafka[MainCluster] shouldBePublished .... No more guessing which Kafka the assertion targeted.
When NOT to use keys¶
Related¶
- Multi-system order recipe
- Provided Application for black-box upstream services
- Provided Instances for shared CI infrastructure