ProductPromotion
Logo

Kotlin

made by https://0x3d.site

GitHub - Trendyol/stove: Stove: The easiest way of writing e2e tests for your JVM back-end API with Kotlin
Stove: The easiest way of writing e2e tests for your JVM back-end API with Kotlin - Trendyol/stove
Visit Site

GitHub - Trendyol/stove: Stove: The easiest way of writing e2e tests for your JVM back-end API with Kotlin

GitHub - Trendyol/stove: Stove: The easiest way of writing e2e tests for your JVM back-end API with Kotlin

What is Stove?

Stove is an end-to-end testing framework that spins up physical dependencies and your application all together. So you have a control over dependencies via Kotlin code.

In the JVM world, thanks to code interoperability, you application code and test can be written with different JVM languages and can be run together. For example, you can write your application code with Java and write your tests with Kotlin, or Application code with Scala and test with Kotlin, etc. Stove uses this ability and provides a way to write your tests in Kotlin.

Your tests will be infra agnostic, but component aware, so they can use easily necessary physical components with Stove provided APIs. All the infra is pluggable, and can be added easily. You can also create your own infra needs by using the abstractions that Stove provides. Having said that, the only dependency is docker since Stove is using testcontainers underlying.

You can use JUnit and Kotest for running the tests. You can run all the tests on your CI, too. But that needs DinD(docker-in-docker) integration.

The medium story about the motivation behind the framework: A New Approach to the API End-to-End Testing in Kotlin

Note: Stove is not a replacement for the unit tests, it is a framework for end-to-end/component tests.

[!NOTE] Some people tend to call these tests as integration tests, some call them as component tests, some call them as end-to-end tests. In this documentation, we will use the term end-to-end tests. We think that the e2e/component tests term is more serving to the purpose of message we want to convey.

What is the problem?

In the JVM world, we have a lot of frameworks for the application code, but when it comes to integration/component/e2e testing we don't have a single framework that can be used for all the tech stacks. We have testcontainers but you still need to do lots of plumbing to make it work with your tech stack.

The use-cases that led us develop the Stove are to increase the productivity of the developers while keeping the quality of the codebase high and coherent.

Those use-cases are:

  • Kotlin app with Spring-Boot
  • Kotlin app with Ktor
  • Java app with Spring-Boot
  • Java app with Micronaut
  • Java app with Quarkus
  • Scala app with Spring-Boot

People have different tech stacks and each time when they want to write e2e tests, they need to write a lot of boilerplate code. Stove is here to solve this problem. It provides a single API to write e2e tests for all the tech stacks.

Stove unifies the testing experience whatever you use.

For more info and how to use: Check the documentation

[!WARNING] Stove is under development and, despite being heavily tested, its API isn't yet stabilized; breaking changes might happen on minor releases. However, we will always provide migration guides.

Report any issue or bug in the GitHub repository.

codecov

Supports

Physical dependencies:

  • Kafka
  • Couchbase
  • HttpClient to make real http calls against the application under test
  • Wiremock to mock all the external dependencies
  • PostgresSql
  • ElasticSearch
  • MongoDB
  • MSSQL
  • Redis

Frameworks:

  • Spring
  • Ktor
  • Quarkus (up for grabs)
  • Micronaut (up for grabs)

Show me the code

šŸ“¹ Youtube Session about how to use (Turkish)

Setting-up all the physical dependencies with application

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()

Testing the entire application with physical dependencies

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
        }
    }
}

More Resources
to explore the angular.

mail [email protected] to add your project or resources here šŸ”„.

Related Articles
to learn about angular.

FAQ's
to learn more about Angular JS.

mail [email protected] to add more queries here šŸ”.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory