Skip to content

Conversation

belljun3395
Copy link
Contributor

@belljun3395 belljun3395 commented Jun 22, 2025

Overview

This PR resolves an issue that occurs when using the Koin dependency injection framework in a Property-Based Testing environment. This is based on the discussion in GitHub issue #2171.

The Problem

When using property-based testing functions like Kotest's checkAll with KoinListener, the Koin context is shared across all iterations of the test. This is because KoinListener only starts and stops the Koin context at the TestCase level, and all iterations within a checkAll block are considered part of a single TestCase.

As a result, an object declared in a Koin module during the first iteration (e.g., declareMock { Repository(arg) }) is reused in subsequent iterations. For example, get<Service>() would always receive Repository(true) in the second run. This violates the fundamental principle of test isolation, where each test run should be independent, thereby undermining the reliability of property-based tests.

The Solution

To address this, this PR introduces KoinPropTestListener, a new listener that implements the PropTestListener interface.

The KoinPropTestListener ensures proper test isolation by starting the Koin context with startKoin immediately before each iteration of a property test begins, and shutting it down with stopKoin immediately after the iteration completes.

Before:

With KoinListener, isolation between property test iterations was not guaranteed.

// Using KoinListener with property-based tests...
checkAll<Boolean> { arg -> // true, false
  declareMock { Repository(arg) }
  get<Service>() // The second iteration would still get Repository(true)
}

After:

KoinPropTestListener creates a fresh Koin context for each iteration, ensuring complete test isolation.

checkAll<Boolean>(
    PropTestConfig(listeners = listOf(KoinPropTestListener(myModule)))
) { a ->
    val currentService: MyService = get { parametersOf(a) }
    currentService.a shouldBe a // A new Service instance is injected every time
}

This change allows developers to reliably use Koin with property-based tests, ensuring that dependencies for each test iteration are managed in a clean and isolated manner.

Related Issue

@belljun3395 belljun3395 requested a review from a team as a code owner June 22, 2025 03:11
Signed-off-by: belljun3395 <195850@jnu.ac.kr>
@belljun3395 belljun3395 force-pushed the feat/add-koin-prop-test-listener branch from 859c8d7 to 19ca2fc Compare June 22, 2025 03:12
@sksamuel sksamuel enabled auto-merge June 25, 2025 00:39
@sksamuel sksamuel added this pull request to the merge queue Jun 25, 2025
@sksamuel
Copy link
Member

Thanks for the Pr

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jun 25, 2025
@belljun3395
Copy link
Contributor Author

스크린샷 2025-06-25 오전 10 21 44

스크린샷 2025-06-25 오전 10 22 25

@sksamuel I updated the branch due to a failure in the GitHub Actions workflow as shown in the screenshot. Is there anything else I need to do?

@sksamuel sksamuel enabled auto-merge June 25, 2025 01:36
@sksamuel
Copy link
Member

Nope. Kicked it off again

@belljun3395
Copy link
Contributor Author

스크린샷 2025-06-26 오후 11 30 48

Please mention me if there’s anything I need to check regarding PR-Test / Run gradle check (macos-latest).

@sksamuel sksamuel added this pull request to the merge queue Jun 26, 2025
Merged via the queue into kotest:master with commit e0d9db4 Jun 26, 2025
17 of 21 checks passed
Kantis pushed a commit to JesusMcCloud/kotest that referenced this pull request Jul 12, 2025
<!-- 
If this PR updates documentation, please update all relevant versions of
the docs, see:
https://github.com/kotest/kotest/tree/master/documentation/versioned_docs
The documentation at
https://github.com/kotest/kotest/tree/master/documentation/docs is the
documentation for the next minor or major version _TO BE RELEASED_
-->
**Overview**

This PR resolves an issue that occurs when using the `Koin` dependency
injection framework in a Property-Based Testing environment. This is
based on the discussion in GitHub issue kotest#2171.

**The Problem**

When using property-based testing functions like Kotest's `checkAll`
with `KoinListener`, the Koin context is shared across all iterations of
the test. This is because `KoinListener` only starts and stops the Koin
context at the `TestCase` level, and all iterations within a `checkAll`
block are considered part of a single `TestCase`.

As a result, an object declared in a Koin module during the first
iteration (e.g., `declareMock { Repository(arg) }`) is reused in
subsequent iterations. For example, `get<Service>()` would always
receive `Repository(true)` in the second run. This violates the
fundamental principle of test isolation, where each test run should be
independent, thereby undermining the reliability of property-based
tests.

**The Solution**

To address this, this PR introduces `KoinPropTestListener`, a new
listener that implements the `PropTestListener` interface.

The `KoinPropTestListener` ensures proper test isolation by starting the
Koin context with `startKoin` immediately before **each iteration** of a
property test begins, and shutting it down with `stopKoin` immediately
after the iteration completes.

**Before:**

With `KoinListener`, isolation between property test iterations was not
guaranteed.

```kotlin
// Using KoinListener with property-based tests...
checkAll<Boolean> { arg -> // true, false
  declareMock { Repository(arg) }
  get<Service>() // The second iteration would still get Repository(true)
}
```

**After:**

`KoinPropTestListener` creates a fresh Koin context for each iteration,
ensuring complete test isolation.

```kotlin
checkAll<Boolean>(
    PropTestConfig(listeners = listOf(KoinPropTestListener(myModule)))
) { a ->
    val currentService: MyService = get { parametersOf(a) }
    currentService.a shouldBe a // A new Service instance is injected every time
}
```

This change allows developers to reliably use `Koin` with property-based
tests, ensuring that dependencies for each test iteration are managed in
a clean and isolated manner.

**Related Issue**

*   Fixes kotest#2171

Signed-off-by: belljun3395 <195850@jnu.ac.kr>
Co-authored-by: Sam <sam@sksamuel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make KoinListener work with property based testing
2 participants