Skip to content

Provided Application (Black-Box)

Skip the local AUT boot. Drive Stove tests against a remote, already-deployed application. The app can be written in any language; Stove treats it as an already-running black-box endpoint.

In 30 seconds Replace your framework starter (springBoot, ktor, goApp) with providedApplication { } plus an optional readiness probe. Wire httpClient to the remote URL. Use .provided(...) on every system that points at staging infrastructure. Stove does not boot the app or inject configuration; verify through public endpoints and provided systems.

When to use

  • Staging validation. Verify deployed services before release
  • Polyglot testing. The app can be Go, Python, .NET, Rust, Node, anything
  • Microservice integration. Drive your service through its public API, verify side effects in shared DBs / Kafka / caches
  • Smoke testing. Post-deployment checks in CI/CD

Configure

providedApplication { } replaces the framework starter in Stove().with. HTTP and other systems are configured as usual, but all application configuration must already exist in the deployed environment.

Stove().with {
  httpClient {
    HttpClientSystemOptions(baseUrl = "https://staging.myapp.com")
  }

  providedApplication {
    ProvidedApplicationOptions(
      readiness = ReadinessStrategy.HttpGet(
        url = "https://staging.myapp.com/actuator/health"
      )
    )
  }
}.run()

Readiness probe

Verifies the remote app is reachable before tests run. If checks fail after all retries, Stove throws with a clear error.

ReadinessStrategy.HttpGet(
  url = "https://staging.myapp.com/health",
  timeout = 30.seconds,
  retries = 10,
  retryDelay = 1.seconds,
  expectedStatusCodes = setOf(200)
)

Skip the probe entirely if you're sure the app is up:

providedApplication()  // no-op runner, satisfies AUT requirement

Full example

class TestConfig : AbstractProjectConfig() {
  override suspend fun beforeProject() {
    Stove().with {
      httpClient {
        HttpClientSystemOptions(baseUrl = "https://staging.myapp.com")
      }

      postgresql {
        PostgresqlOptions.provided(
          jdbcUrl = "jdbc:postgresql://staging-db:5432/myapp",
          host = "staging-db",
          port = 5432,
          configureExposedConfiguration = { emptyList() }
        )
      }

      kafka {
        KafkaSystemOptions.provided(
          bootstrapServers = "staging-kafka:9092",
          configureExposedConfiguration = { emptyList() }
        )
      }

      providedApplication {
        ProvidedApplicationOptions(
          readiness = ReadinessStrategy.HttpGet(
            url = "https://staging.myapp.com/actuator/health",
            timeout = 15.seconds
          )
        )
      }
    }.run()
  }

  override suspend fun afterProject() = Stove.stop()
}

Writing tests

Use the same registered system DSL where the underlying system can be reached from the test process. DI bridge access through using<T> { } is unavailable for providedApplication(). Kafka observer assertions such as shouldBePublished and shouldBeConsumed only work if the remote app is separately configured to report to Stove; otherwise use direct consumers and system assertions.

test("create order, verify side effects on staging") {
  stove {
    http {
      postAndExpectJson<OrderResponse>("/orders", body = request.some()) { order ->
        order.id shouldNotBe null
      }
    }

    postgresql {
      shouldQuery<Order>(
        "SELECT * FROM orders WHERE id = ?",
        listOf(orderId)
      ) { rows ->
        rows shouldHaveSize 1
      }
    }

    kafka {
      // use consumer() to read directly. no interceptor inside the AUT
      consumer<String, OrderCreatedEvent>("orders.output", readOnly = true) { record ->
        record.value().orderId shouldBe orderId
      }
    }
  }
}

What works, what doesn't

Feature Available? Notes
HTTP / gRPC assertions httpClient { }, grpc { }
Database queries postgresql { }, mongodb { }, ... Via .provided(...)
Kafka publish() + consumer() Direct producer / consumer access
Kafka shouldBeConsumed Requires interceptor inside the AUT
using<T> { } (Bridge) Remote DI container inaccessible

Bridge isn't supported

using<MyService> { } reaches into the AUT's DI container. That is only possible when the AUT runs in the same JVM. Provided applications get a clear error.

Suggested source-set layout

my-service/
  src/
    main/            application code
    test/            unit tests
    test-e2e/        local Stove e2e (app boots in JVM)
    test-blackbox/   Stove smoke tests (providedApplication)