testApplication

This commit is contained in:
2025-03-27 11:57:58 +01:00
parent 027747a20b
commit 933907b608
7 changed files with 95 additions and 115 deletions

View File

@@ -5,6 +5,9 @@ import eventDemo.business.entity.Deck
import eventDemo.configuration.injection.appKoinModule import eventDemo.configuration.injection.appKoinModule
import eventDemo.configuration.ktor.configuration import eventDemo.configuration.ktor.configuration
import io.ktor.server.config.ApplicationConfig 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.Koin
import org.koin.core.module.KoinApplicationDslMarker import org.koin.core.module.KoinApplicationDslMarker
import org.koin.dsl.koinApplication import org.koin.dsl.koinApplication
@@ -16,8 +19,21 @@ fun Deck.allCards(): Set<Card> =
stack + discard + playersHands.values.flatten() stack + discard + playersHands.values.flatten()
@KoinApplicationDslMarker @KoinApplicationDslMarker
suspend fun testApplicationWithConfig(block: suspend Koin.() -> Unit) { suspend fun testKoinApplicationWithConfig(block: suspend Koin.() -> Unit) {
koinApplication { modules(appKoinModule(ApplicationConfig("application.conf").configuration())) }.koin.apply { koinApplication { modules(appKoinModule(ApplicationConfig("application.conf").configuration())) }.koin.apply {
block() 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)
}
}

View File

@@ -1,12 +1,9 @@
package eventDemo.adapter.infrastructureLayer package eventDemo.adapter.infrastructureLayer
import eventDemo.configuration.configure import eventDemo.testKoinApplicationWithConfig
import io.kotest.core.NamedTag import io.kotest.core.NamedTag
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.equals.shouldBeEqual 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 import javax.sql.DataSource
class PostgresqlTest : class PostgresqlTest :
@@ -14,11 +11,7 @@ class PostgresqlTest :
tags(NamedTag("postgresql")) tags(NamedTag("postgresql"))
test("test connection with postgresql") { test("test connection with postgresql") {
testApplication { testKoinApplicationWithConfig {
application {
stopKoin()
configure()
val datasource by inject<DataSource>() val datasource by inject<DataSource>()
datasource.connection.use { connection -> datasource.connection.use { connection ->
connection connection
@@ -33,5 +26,4 @@ class PostgresqlTest :
} }
} }
} }
}
}) })

View File

@@ -7,7 +7,7 @@ import eventDemo.business.event.event.GameStartedEvent
import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.event.PlayerReadyEvent import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.projection.gameList.GameList import eventDemo.business.event.projection.gameList.GameList
import eventDemo.configuration.configure import eventDemo.testApplicationWithConfig
import io.kotest.assertions.nondeterministic.eventually import io.kotest.assertions.nondeterministic.eventually
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContain 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.client.statement.bodyAsText
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.testing.testApplication
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.koin.core.context.stopKoin
import org.koin.ktor.ext.inject
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@@ -30,12 +27,9 @@ import kotlin.time.Duration.Companion.seconds
class GameListRouteTest : class GameListRouteTest :
FunSpec({ FunSpec({
test("/games with no game started") { test("/games with no game started") {
testApplication {
testApplicationWithConfig {
val player1 = Player(name = "Nikola") val player1 = Player(name = "Nikola")
application {
stopKoin()
configure()
}
httpClient() httpClient()
.get("/games") { .get("/games") {
@@ -50,19 +44,14 @@ class GameListRouteTest :
} }
test("/games return a game with status OPENING") { test("/games return a game with status OPENING") {
testApplication { testApplicationWithConfig { koin ->
val gameId = GameId() val gameId = GameId()
val player1 = Player(name = "Nikola") val player1 = Player(name = "Nikola")
application { val eventHandler = koin.get<GameEventHandler>()
stopKoin()
configure()
val eventHandler by inject<GameEventHandler>()
runBlocking { runBlocking {
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) }
} }
}
// Wait until the projection is created // Wait until the projection is created
eventually(3.seconds) { eventually(3.seconds) {
@@ -84,16 +73,11 @@ class GameListRouteTest :
} }
test("/games return a game with status IS_STARTED") { test("/games return a game with status IS_STARTED") {
testApplication { testApplicationWithConfig { koin ->
val gameId = GameId() val gameId = GameId()
val player1 = Player(name = "Nikola") val player1 = Player(name = "Nikola")
val player2 = Player(name = "Einstein") val player2 = Player(name = "Einstein")
val eventHandler = koin.get<GameEventHandler>()
application {
stopKoin()
configure()
val eventHandler by inject<GameEventHandler>()
runBlocking { runBlocking {
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) }
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) }
@@ -108,7 +92,6 @@ class GameListRouteTest :
) )
} }
} }
}
httpClient() httpClient()
.get("/games") { .get("/games") {

View File

@@ -23,7 +23,7 @@ import eventDemo.business.notification.PlayerWasReadyNotification
import eventDemo.business.notification.TheGameWasStartedNotification import eventDemo.business.notification.TheGameWasStartedNotification
import eventDemo.business.notification.WelcomeToTheGameNotification import eventDemo.business.notification.WelcomeToTheGameNotification
import eventDemo.libs.event.projection.ProjectionSnapshotRepositoryInMemory import eventDemo.libs.event.projection.ProjectionSnapshotRepositoryInMemory
import eventDemo.testApplicationWithConfig import eventDemo.testKoinApplicationWithConfig
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.equals.shouldBeEqual import io.kotest.matchers.equals.shouldBeEqual
@@ -169,7 +169,7 @@ class GameSimulationTest :
} }
} }
testApplicationWithConfig { testKoinApplicationWithConfig {
val commandHandler by inject<GameCommandHandler>() val commandHandler by inject<GameCommandHandler>()
val eventStore by inject<GameEventStore>() val eventStore by inject<GameEventStore>()
val playerNotificationListener by inject<PlayerNotificationListener>() val playerNotificationListener by inject<PlayerNotificationListener>()

View File

@@ -10,7 +10,7 @@ import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.event.PlayerReadyEvent import eventDemo.business.event.event.PlayerReadyEvent
import eventDemo.business.event.projection.gameState.GameState import eventDemo.business.event.projection.gameState.GameState
import eventDemo.business.event.projection.gameState.GameStateRepository import eventDemo.business.event.projection.gameState.GameStateRepository
import eventDemo.configuration.configure import eventDemo.testApplicationWithConfig
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.equals.shouldBeEqual 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.client.statement.bodyAsText
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.testing.testApplication
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.koin.core.context.stopKoin
import org.koin.ktor.ext.inject
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertIs import kotlin.test.assertIs
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
@@ -32,13 +29,9 @@ import kotlin.test.assertNotNull
class GameStateRouteTest : class GameStateRouteTest :
FunSpec({ FunSpec({
test("/games/{id}/state on empty game") { test("/games/{id}/state on empty game") {
testApplication { testApplicationWithConfig {
val id = GameId() val id = GameId()
val player1 = Player(name = "Nikola") val player1 = Player(name = "Nikola")
application {
stopKoin()
configure()
}
httpClient() httpClient()
.get("/games/$id/state") { .get("/games/$id/state") {
@@ -55,18 +48,15 @@ class GameStateRouteTest :
} }
test("/games/{id}/card/last") { test("/games/{id}/card/last") {
testApplication { testApplicationWithConfig { koin ->
val gameId = GameId() val gameId = GameId()
val player1 = Player(name = "Nikola") val player1 = Player(name = "Nikola")
val player2 = Player(name = "Einstein") val player2 = Player(name = "Einstein")
var lastPlayedCard: Card? = null var lastPlayedCard: Card? = null
application { val eventHandler = koin.get<GameEventHandler>()
stopKoin() val stateRepo = koin.get<GameStateRepository>()
configure()
val eventHandler by inject<GameEventHandler>()
val stateRepo by inject<GameStateRepository>()
runBlocking { runBlocking {
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) } eventHandler.handle(gameId) { NewPlayerEvent(gameId, player1, it) }
eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) } eventHandler.handle(gameId) { NewPlayerEvent(gameId, player2, it) }
@@ -99,7 +89,6 @@ class GameStateRouteTest :
} }
delay(100) delay(100)
} }
}
httpClient() httpClient()
.get("/games/$gameId/card/last") { .get("/games/$gameId/card/last") {

View File

@@ -9,7 +9,7 @@ import eventDemo.business.event.projection.projectionListener.ReactionListener
import eventDemo.business.notification.CommandSuccessNotification import eventDemo.business.notification.CommandSuccessNotification
import eventDemo.business.notification.Notification import eventDemo.business.notification.Notification
import eventDemo.business.notification.WelcomeToTheGameNotification import eventDemo.business.notification.WelcomeToTheGameNotification
import eventDemo.testApplicationWithConfig import eventDemo.testKoinApplicationWithConfig
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContain import io.kotest.matchers.collections.shouldContain
import io.kotest.matchers.equals.shouldBeEqual import io.kotest.matchers.equals.shouldBeEqual
@@ -27,7 +27,7 @@ class GameCommandHandlerTest :
FunSpec({ FunSpec({
test("handle a command should execute the command") { test("handle a command should execute the command") {
withTimeout(1.seconds) { withTimeout(1.seconds) {
testApplicationWithConfig { testKoinApplicationWithConfig {
val commandHandler by inject<GameCommandHandler>() val commandHandler by inject<GameCommandHandler>()
val notificationListener by inject<PlayerNotificationListener>() val notificationListener by inject<PlayerNotificationListener>()
val gameId = GameId() val gameId = GameId()

View File

@@ -6,7 +6,7 @@ import eventDemo.business.event.GameEventHandler
import eventDemo.business.event.event.NewPlayerEvent import eventDemo.business.event.event.NewPlayerEvent
import eventDemo.business.event.projection.gameState.GameState import eventDemo.business.event.projection.gameState.GameState
import eventDemo.business.event.projection.gameState.GameStateRepository import eventDemo.business.event.projection.gameState.GameStateRepository
import eventDemo.testApplicationWithConfig import eventDemo.testKoinApplicationWithConfig
import io.kotest.assertions.nondeterministic.eventually import io.kotest.assertions.nondeterministic.eventually
import io.kotest.assertions.nondeterministic.eventuallyConfig import io.kotest.assertions.nondeterministic.eventuallyConfig
import io.kotest.core.spec.style.FunSpec import io.kotest.core.spec.style.FunSpec
@@ -30,7 +30,7 @@ class GameStateRepositoryTest :
test("GameStateRepository should build the projection when a new event occurs") { test("GameStateRepository should build the projection when a new event occurs") {
val aggregateId = GameId() val aggregateId = GameId()
testApplicationWithConfig { testKoinApplicationWithConfig {
val repo = get<GameStateRepository>() val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>() val eventHandler = get<GameEventHandler>()
eventHandler eventHandler
@@ -52,7 +52,7 @@ class GameStateRepositoryTest :
test("get should build the last version of the state") { test("get should build the last version of the state") {
val aggregateId = GameId() val aggregateId = GameId()
testApplicationWithConfig { testKoinApplicationWithConfig {
val repo = get<GameStateRepository>() val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>() val eventHandler = get<GameEventHandler>()
val projectionBus = get<GameProjectionBus>() val projectionBus = get<GameProjectionBus>()
@@ -88,7 +88,7 @@ class GameStateRepositoryTest :
test("getUntil should build the state until the event") { test("getUntil should build the state until the event") {
repeat(10) { repeat(10) {
val aggregateId = GameId() val aggregateId = GameId()
testApplicationWithConfig { testKoinApplicationWithConfig {
val repo = get<GameStateRepository>() val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>() val eventHandler = get<GameEventHandler>()
@@ -117,7 +117,7 @@ class GameStateRepositoryTest :
test("getUntil should be concurrently secure") { test("getUntil should be concurrently secure") {
val aggregateId = GameId() val aggregateId = GameId()
testApplicationWithConfig { testKoinApplicationWithConfig {
val repo = get<GameStateRepository>() val repo = get<GameStateRepository>()
val eventHandler = get<GameEventHandler>() val eventHandler = get<GameEventHandler>()