Clean Architecture Masterclass

Clean Architecture MasterclassMay 28-29

Join

Stove

❝Where the infrastructure burns down to pure configurations(ashes)❞

Release codecov OpenSSF Scorecard

What is Stove?

Stove is an end-to-end testing framework that simplifies testing by managing physical dependencies and your application in a unified way. Write infrastructure-agnostic but component-aware tests in Kotlin, regardless of your JVM-based tech stack.

Key Features

Supported Infrastructure

Physical dependencies:

Frameworks:

Quick Start

Add the dependency

// Add the following dependencies to your build.gradle.kts
testImplementation("com.trendyol:stove-testing-e2e:${version}")

// And the any of the following for the infrastructure you want to use, for example Kafka
// you can also use Couchbase, PostgreSQL, ElasticSearch, MongoDB, MSSQL, Redis, HTTP Client, WireMock
// as much as you want
testImplementation("com.trendyol:stove-testing-e2e-kafka:${version}")

// And Application Under Test (AUT)
testImplementation("com.trendyol:stove-ktor-testing-e2e:${version}")

// Or
testImplementation("com.trendyol:stove-spring-testing-e2e:${version}")

Set Up the TestSystem

TestSystem() {
  if (isRunningLocally()) {
    enableReuseForTestContainers()

    // this will keep the dependencies running
    // after the tests are finished,
    // so next run will be blazing fast :)
    keepDendenciesRunning()
  }
}.with {
  // Enables http client 
  // to make real http calls 
  // against the application under test
  httpClient {
    HttpClientSystemOptions(
      baseUrl = "http://localhost:8001",
    )
  }

  // Enables Couchbase physically 
  // and exposes the configuration 
  // to the application under test
  couchbase {
    CouchbaseSystemOptions(
      defaultBucket = "Stove",
      configureExposedConfiguration = { cfg -> listOf("couchbase.hosts=${cfg.hostsWithPort}") },
    )
  }

  // Enables Kafka physically 
  // and exposes the configuration 
  // to the application under test
  kafka {
    KafkaSystemOptions(
      configureExposedConfiguration = { cfg -> listOf("kafka.bootstrapServers=${cfg.boostrapServers}") },
    )
  }

  // Enables Wiremock on the given port 
  // and provides configurable mock HTTP server 
  // for your external API calls
  wiremock {
    WireMockSystemOptions(
      port = 9090,
      removeStubAfterRequestMatched = true,
      afterRequest = { e, _, _ ->
        logger.info(e.request.toString())
      },
    )
  }

  // The Application Under Test. 
  // Enables Spring Boot application 
  // to be run with the given parameters.
  springBoot(
    runner = { parameters ->
      stove.spring.example.run(parameters) { it.addTestSystemDependencies() }
    },
    withParameters = listOf(
      "server.port=8001",
      "logging.level.root=warn",
      "logging.level.org.springframework.web=warn",
      "spring.profiles.active=default",
      "kafka.heartbeatInSeconds=2",
    ),
  )
}.run()

Write Tests

TestSystem.validate {
  wiremock {
    mockGet("/example-url", responseBody = None, statusCode = 200)
  }

  http {
    get<String>("/hello/index") { actual ->
      actual shouldContain "Hi from Stove framework"
      println(actual)
    }
  }

  couchbase {
    shouldQuery<Any>("SELECT * FROM system:keyspaces") { actual ->
      println(actual)
    }
  }

  kafka {
    shouldBePublished<ExampleMessage> {
      actual.aggregateId == 123
          && metadata.topic = "example-topic"
          && metadata.headers["example-header"] == "example-value"
    }
    shouldBeConsumed<ExampleMessage> {
      actual.aggregateId == 123
          && metadata.topic = "example-topic"
          && metadata.headers["example-header"] == "example-value"
    }
  }

  couchbase {
    save(collection = "Backlogs", id = "id-of-backlog", instance = Backlog("id-of-backlog"))
  }

  http {
    postAndExpectBodilessResponse("/backlog/reserve") { actual ->
      actual.status.shouldBe(200)
    }
  }

  kafka {
    shouldBeConsumed<ProductCreated> {
      actual.aggregateId == expectedId
    }
  }
}

Why Stove?

The JVM ecosystem lacks a unified approach to end-to-end testing. While tools like Testcontainers exist, developers still need to:

This affects teams across many tech stacks:

Stove solves these challenges by providing:

Stove unifies the testing experience across all JVM stacks, making it easier to write clean, focused tests.

Resources

Status

[!WARNING] While Stove is production-ready and extensively used, the API is not yet fully stabilized. Breaking changes may occur in minor releases, but migration guides will always be provided.

Contributing

Contributions are welcome! Whether it's:

License

Stove is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.

Join libs.tech

...and unlock some superpowers

GitHub

We won't share your data with anyone else.