From 933907b608c03c3ce17349ce4a93f96ff6171a5b Mon Sep 17 00:00:00 2001 From: Fabrice Lecomte Date: Thu, 27 Mar 2025 11:57:58 +0100 Subject: [PATCH] testApplication --- src/test/kotlin/eventDemo/Helpers.kt | 18 ++++- .../infrastructureLayer/PostgresqlTest.kt | 34 +++----- .../interfaceLayer/query/GameListRouteTest.kt | 59 +++++--------- .../query/GameSimulationTest.kt | 4 +- .../query/GameStateRouteTest.kt | 81 ++++++++----------- .../command/GameCommandHandlerTest.kt | 4 +- .../projection/GameStateRepositoryTest.kt | 10 +-- 7 files changed, 95 insertions(+), 115 deletions(-) diff --git a/src/test/kotlin/eventDemo/Helpers.kt b/src/test/kotlin/eventDemo/Helpers.kt index 691f5d1..2a2a1f1 100644 --- a/src/test/kotlin/eventDemo/Helpers.kt +++ b/src/test/kotlin/eventDemo/Helpers.kt @@ -5,6 +5,9 @@ import eventDemo.business.entity.Deck import eventDemo.configuration.injection.appKoinModule import eventDemo.configuration.ktor.configuration import io.ktor.server.config.ApplicationConfig +import io.ktor.server.testing.ApplicationTestBuilder +import io.ktor.server.testing.testApplication +import io.ktor.utils.io.KtorDsl import org.koin.core.Koin import org.koin.core.module.KoinApplicationDslMarker import org.koin.dsl.koinApplication @@ -16,8 +19,21 @@ fun Deck.allCards(): Set = stack + discard + playersHands.values.flatten() @KoinApplicationDslMarker -suspend fun testApplicationWithConfig(block: suspend Koin.() -> Unit) { +suspend fun testKoinApplicationWithConfig(block: suspend Koin.() -> Unit) { koinApplication { modules(appKoinModule(ApplicationConfig("application.conf").configuration())) }.koin.apply { block() } } + +@KtorDsl +suspend fun testApplicationWithConfig(block: suspend ApplicationTestBuilder.(koin: Koin) -> Unit) { + testApplication { + val conf = ApplicationConfig("application.conf") + environment { + config = conf + } + + val koin = koinApplication { modules(appKoinModule(conf.configuration())) }.koin + block(koin) + } +} diff --git a/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt b/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt index fa034b2..531df77 100644 --- a/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt +++ b/src/test/kotlin/eventDemo/adapter/infrastructureLayer/PostgresqlTest.kt @@ -1,12 +1,9 @@ package eventDemo.adapter.infrastructureLayer -import eventDemo.configuration.configure +import eventDemo.testKoinApplicationWithConfig import io.kotest.core.NamedTag import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.equals.shouldBeEqual -import io.ktor.server.testing.testApplication -import org.koin.core.context.stopKoin -import org.koin.ktor.ext.inject import javax.sql.DataSource class PostgresqlTest : @@ -14,23 +11,18 @@ class PostgresqlTest : tags(NamedTag("postgresql")) test("test connection with postgresql") { - testApplication { - application { - stopKoin() - configure() - - val datasource by inject() - datasource.connection.use { connection -> - connection - .prepareStatement( - """ - select 1; - """.trimIndent(), - ).execute() - .let { - it shouldBeEqual true - } - } + testKoinApplicationWithConfig { + val datasource by inject() + datasource.connection.use { connection -> + connection + .prepareStatement( + """ + select 1; + """.trimIndent(), + ).execute() + .let { + it shouldBeEqual true + } } } } diff --git a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameListRouteTest.kt b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameListRouteTest.kt index 493f30c..40fc564 100644 --- a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameListRouteTest.kt +++ b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameListRouteTest.kt @@ -7,7 +7,7 @@ import eventDemo.business.event.event.GameStartedEvent import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.event.PlayerReadyEvent import eventDemo.business.event.projection.gameList.GameList -import eventDemo.configuration.configure +import eventDemo.testApplicationWithConfig import io.kotest.assertions.nondeterministic.eventually import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldContain @@ -19,10 +19,7 @@ import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode -import io.ktor.server.testing.testApplication import kotlinx.coroutines.runBlocking -import org.koin.core.context.stopKoin -import org.koin.ktor.ext.inject import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.time.Duration.Companion.seconds @@ -30,12 +27,9 @@ import kotlin.time.Duration.Companion.seconds class GameListRouteTest : FunSpec({ test("/games with no game started") { - testApplication { + + testApplicationWithConfig { val player1 = Player(name = "Nikola") - application { - stopKoin() - configure() - } httpClient() .get("/games") { @@ -50,18 +44,13 @@ class GameListRouteTest : } test("/games return a game with status OPENING") { - testApplication { + testApplicationWithConfig { koin -> val gameId = GameId() val player1 = Player(name = "Nikola") - application { - stopKoin() - configure() - - val eventHandler by inject() - runBlocking { - eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } - } + val eventHandler = koin.get() + runBlocking { + eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } } // Wait until the projection is created @@ -84,29 +73,23 @@ class GameListRouteTest : } test("/games return a game with status IS_STARTED") { - testApplication { + testApplicationWithConfig { koin -> val gameId = GameId() val player1 = Player(name = "Nikola") val player2 = Player(name = "Einstein") - - application { - stopKoin() - configure() - - val eventHandler by inject() - runBlocking { - eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } - eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } - eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) } - eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) } - eventHandler.handle(gameId) { - GameStartedEvent.new( - gameId, - setOf(player1, player2), - it, - shuffleIsDisabled = true, - ) - } + val eventHandler = koin.get() + runBlocking { + eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } + eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } + eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) } + eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) } + eventHandler.handle(gameId) { + GameStartedEvent.new( + gameId, + setOf(player1, player2), + it, + shuffleIsDisabled = true, + ) } } diff --git a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameSimulationTest.kt b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameSimulationTest.kt index f84b017..a4f3b32 100644 --- a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameSimulationTest.kt +++ b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameSimulationTest.kt @@ -23,7 +23,7 @@ import eventDemo.business.notification.PlayerWasReadyNotification import eventDemo.business.notification.TheGameWasStartedNotification import eventDemo.business.notification.WelcomeToTheGameNotification import eventDemo.libs.event.projection.ProjectionSnapshotRepositoryInMemory -import eventDemo.testApplicationWithConfig +import eventDemo.testKoinApplicationWithConfig import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.equals.shouldBeEqual @@ -169,7 +169,7 @@ class GameSimulationTest : } } - testApplicationWithConfig { + testKoinApplicationWithConfig { val commandHandler by inject() val eventStore by inject() val playerNotificationListener by inject() diff --git a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameStateRouteTest.kt b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameStateRouteTest.kt index d732a1f..a93e438 100644 --- a/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameStateRouteTest.kt +++ b/src/test/kotlin/eventDemo/adapter/interfaceLayer/query/GameStateRouteTest.kt @@ -10,7 +10,7 @@ import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.event.PlayerReadyEvent import eventDemo.business.event.projection.gameState.GameState import eventDemo.business.event.projection.gameState.GameStateRepository -import eventDemo.configuration.configure +import eventDemo.testApplicationWithConfig import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.equals.shouldBeEqual @@ -20,11 +20,8 @@ import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode -import io.ktor.server.testing.testApplication import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking -import org.koin.core.context.stopKoin -import org.koin.ktor.ext.inject import kotlin.test.assertEquals import kotlin.test.assertIs import kotlin.test.assertNotNull @@ -32,13 +29,9 @@ import kotlin.test.assertNotNull class GameStateRouteTest : FunSpec({ test("/games/{id}/state on empty game") { - testApplication { + testApplicationWithConfig { val id = GameId() val player1 = Player(name = "Nikola") - application { - stopKoin() - configure() - } httpClient() .get("/games/$id/state") { @@ -55,50 +48,46 @@ class GameStateRouteTest : } test("/games/{id}/card/last") { - testApplication { + testApplicationWithConfig { koin -> val gameId = GameId() val player1 = Player(name = "Nikola") val player2 = Player(name = "Einstein") var lastPlayedCard: Card? = null - application { - stopKoin() - configure() + val eventHandler = koin.get() + val stateRepo = koin.get() - val eventHandler by inject() - val stateRepo by inject() - runBlocking { - eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } - eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } - eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) } - eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) } - eventHandler.handle(gameId) { - GameStartedEvent.new( - gameId, - setOf(player1, player2), - it, - shuffleIsDisabled = true, - ) - } - delay(100) - lastPlayedCard = stateRepo.getLast(gameId).playableCards(player1).first() - assertNotNull(lastPlayedCard) - .let { assertIs(lastPlayedCard) } - .let { - it.number shouldBeEqual 0 - it.color shouldBeEqual Card.Color.Red - } - delay(100) - eventHandler.handle(gameId) { - CardIsPlayedEvent( - gameId, - assertNotNull(lastPlayedCard), - player1, - it, - ) - } - delay(100) + runBlocking { + eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } + eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } + eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player1, it) } + eventHandler.handle(gameId) { PlayerReadyEvent(gameId, player2, it) } + eventHandler.handle(gameId) { + GameStartedEvent.new( + gameId, + setOf(player1, player2), + it, + shuffleIsDisabled = true, + ) } + delay(100) + lastPlayedCard = stateRepo.getLast(gameId).playableCards(player1).first() + assertNotNull(lastPlayedCard) + .let { assertIs(lastPlayedCard) } + .let { + it.number shouldBeEqual 0 + it.color shouldBeEqual Card.Color.Red + } + delay(100) + eventHandler.handle(gameId) { + CardIsPlayedEvent( + gameId, + assertNotNull(lastPlayedCard), + player1, + it, + ) + } + delay(100) } httpClient() diff --git a/src/test/kotlin/eventDemo/business/command/GameCommandHandlerTest.kt b/src/test/kotlin/eventDemo/business/command/GameCommandHandlerTest.kt index 8f42033..9acd132 100644 --- a/src/test/kotlin/eventDemo/business/command/GameCommandHandlerTest.kt +++ b/src/test/kotlin/eventDemo/business/command/GameCommandHandlerTest.kt @@ -9,7 +9,7 @@ import eventDemo.business.event.projection.projectionListener.ReactionListener import eventDemo.business.notification.CommandSuccessNotification import eventDemo.business.notification.Notification import eventDemo.business.notification.WelcomeToTheGameNotification -import eventDemo.testApplicationWithConfig +import eventDemo.testKoinApplicationWithConfig import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.equals.shouldBeEqual @@ -27,7 +27,7 @@ class GameCommandHandlerTest : FunSpec({ test("handle a command should execute the command") { withTimeout(1.seconds) { - testApplicationWithConfig { + testKoinApplicationWithConfig { val commandHandler by inject() val notificationListener by inject() val gameId = GameId() diff --git a/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt b/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt index 00d306e..41be9a2 100644 --- a/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt +++ b/src/test/kotlin/eventDemo/business/event/projection/GameStateRepositoryTest.kt @@ -6,7 +6,7 @@ import eventDemo.business.event.GameEventHandler import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.projection.gameState.GameState import eventDemo.business.event.projection.gameState.GameStateRepository -import eventDemo.testApplicationWithConfig +import eventDemo.testKoinApplicationWithConfig import io.kotest.assertions.nondeterministic.eventually import io.kotest.assertions.nondeterministic.eventuallyConfig import io.kotest.core.spec.style.FunSpec @@ -30,7 +30,7 @@ class GameStateRepositoryTest : test("GameStateRepository should build the projection when a new event occurs") { val aggregateId = GameId() - testApplicationWithConfig { + testKoinApplicationWithConfig { val repo = get() val eventHandler = get() eventHandler @@ -52,7 +52,7 @@ class GameStateRepositoryTest : test("get should build the last version of the state") { val aggregateId = GameId() - testApplicationWithConfig { + testKoinApplicationWithConfig { val repo = get() val eventHandler = get() val projectionBus = get() @@ -88,7 +88,7 @@ class GameStateRepositoryTest : test("getUntil should build the state until the event") { repeat(10) { val aggregateId = GameId() - testApplicationWithConfig { + testKoinApplicationWithConfig { val repo = get() val eventHandler = get() @@ -117,7 +117,7 @@ class GameStateRepositoryTest : test("getUntil should be concurrently secure") { val aggregateId = GameId() - testApplicationWithConfig { + testKoinApplicationWithConfig { val repo = get() val eventHandler = get()