diff --git a/README.md b/README.md
index a656b2c6de75c4d6891b023e298b88a3a7f58ea0..afe3e094387c1875fd39b29ac5e940e18f271bec 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,8 @@ Place yourself at root and start
 docker compose up -d
 ```
 
+// or with cmd
+
 ## Available endpoints
 
 ## Technical choices
@@ -45,6 +47,16 @@ docker compose up -d
 - [x] tous les endpoints demandés
 - [ ] gestion de la sécurité
 
+Dans l'ordre :
+
+- Amélioration du fonctionnel
+    - Routes factorisées
+    - DTO
+    - Appels à la BD
+- Amélioration des tests
+- Amélioration de la sécurité
+- Déploiement en prod serein
+
 ## Going further
 
 - Database migration tool
diff --git a/build.gradle.kts b/build.gradle.kts
index 29241d06ad503adf9291ccea55da2283200770e9..4bd559ef78b96f41a6eb22d4a3d101a3b2cb6d43 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -5,6 +5,9 @@ val dynamo_version: String by project
 val dynamo_kt_version: String by project
 val mockk_version: String by project
 val kotlin_reactive_version: String by project
+val koin_test_version: String by project
+val assertj_core_version: String by project
+val localstack_version: String by project
 
 
 plugins {
@@ -53,4 +56,7 @@ dependencies {
     testImplementation("io.ktor:ktor-server-test-host")
     testImplementation("io.mockk:mockk:$mockk_version")
     testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
+    testImplementation("io.insert-koin:koin-test:$koin_test_version")
+    testImplementation("org.assertj:assertj-core:$assertj_core_version")
+    testImplementation("org.testcontainers:localstack:$localstack_version")
 }
diff --git a/gradle.properties b/gradle.properties
index 89aec6c45909d73e9f16cddef3437b8807ab3e04..8e7826fecd85f8752afc6a54877dd9756395a236 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,3 +7,6 @@ ktor_version=2.3.13
 logback_version=1.4.14
 mockk_version=1.10.0
 kotlin_reactive_version=1.9.0
+koin_test_version=3.4.0
+assertj_core_version=3.24.2
+localstack_version=1.20.4
\ No newline at end of file
diff --git a/src/main/kotlin/Application.kt b/src/main/kotlin/Application.kt
index 6e183effb698210cc51d727ab4bb6451811fe3e6..cca5f445e2e2230e918f5278c039653890e1c809 100644
--- a/src/main/kotlin/Application.kt
+++ b/src/main/kotlin/Application.kt
@@ -4,6 +4,7 @@ import betclic.test.configuration.configureHTTP
 import betclic.test.configuration.configureKoin
 import betclic.test.configuration.configureRouting
 import betclic.test.configuration.configureSerialization
+import betclic.test.configuration.migrateTables
 import io.ktor.server.application.*
 import kotlinx.coroutines.runBlocking
 
@@ -11,9 +12,18 @@ fun main(args: Array<String>) {
     io.ktor.server.netty.EngineMain.main(args)
 }
 
-fun Application.module() = runBlocking {
+fun Application.module() {
+    configuration()
+    initialize()
+}
+
+fun Application.configuration() {
     configureHTTP()
     configureKoin()
     configureSerialization()
     configureRouting()
 }
+
+fun Application.initialize() = runBlocking {
+    migrateTables()
+}
\ No newline at end of file
diff --git a/src/main/kotlin/configuration/DynamoDbConfiguration.kt b/src/main/kotlin/configuration/DynamoDbConfiguration.kt
index 1ef94811b659922806b3a066bd706cd99ecc6b47..59107e39056b385b36b9d69fd56982b48834e33c 100644
--- a/src/main/kotlin/configuration/DynamoDbConfiguration.kt
+++ b/src/main/kotlin/configuration/DynamoDbConfiguration.kt
@@ -1,52 +1,21 @@
 package betclic.test.configuration
 
-import betclic.test.player.PlayerEntity
-import dev.andrewohara.dynamokt.DataClassTableSchema
-import io.ktor.server.application.*
-import kotlinx.coroutines.future.await
 import org.slf4j.LoggerFactory
 import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient
 import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
 import java.net.URI
-import kotlin.reflect.KClass
 
-class DynamoDbConfiguration() {
+class DynamoDbConfiguration {
     private val logger = LoggerFactory.getLogger(DynamoDbConfiguration::class.java)
-    fun dataSource(): DynamoDbEnhancedAsyncClient {
-        logger.info("Using dynamo-db config")
-        return DynamoDbEnhancedAsyncClient.builder()
-            .dynamoDbClient(createDynamoDbClient())
-            .build()
-    }
-}
-
-private fun createDynamoDbClient(): DynamoDbAsyncClient {
-    return DynamoDbAsyncClient.builder().endpointOverride(URI("http://localhost:8000")).build()
-}
 
-suspend fun createNecessaryTables(
-    dynamoDbClient: DynamoDbAsyncClient,
-    dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient
-) {
-    val existingTables = dynamoDbClient.listTables().await().tableNames().toList()
-
-    listOf(PlayerEntity::class).forEach {
-        createTableIfNotExists(existingTables, it, dynamoDbEnhancedClient)
+    fun createDynamoDbClient(): DynamoDbAsyncClient {
+        return DynamoDbAsyncClient.builder().endpointOverride(URI("http://localhost:8000")).build()
     }
-}
-
-private val logger = LoggerFactory.getLogger(Application::class.java)
 
-private suspend fun <T : Any> createTableIfNotExists(
-    existingTables: List<String>,
-    item: KClass<T>,
-    dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient
-) {
-    val tableSchema = DataClassTableSchema(item)
-    if (existingTables.contains(item.simpleName)) {
-        logger.info("Table '${item.simpleName}' already exists.")
-    } else {
-        dynamoDbEnhancedClient.table(item.simpleName, tableSchema).createTable().await()
-        logger.info("Table '${item.simpleName}' created successfully.")
+    fun createDataSource(dynamoDbAsyncClient: DynamoDbAsyncClient): DynamoDbEnhancedAsyncClient {
+        logger.info("Using dynamo-db config")
+        return DynamoDbEnhancedAsyncClient.builder()
+            .dynamoDbClient(dynamoDbAsyncClient)
+            .build()
     }
 }
\ No newline at end of file
diff --git a/src/main/kotlin/configuration/DynamoDbMigration.kt b/src/main/kotlin/configuration/DynamoDbMigration.kt
new file mode 100644
index 0000000000000000000000000000000000000000..b5e4535eeb4b505fd0dd50f12b18f0c39fde4e78
--- /dev/null
+++ b/src/main/kotlin/configuration/DynamoDbMigration.kt
@@ -0,0 +1,53 @@
+package betclic.test.configuration
+
+import betclic.test.player.PlayerEntity
+import dev.andrewohara.dynamokt.DataClassTableSchema
+import io.ktor.server.application.*
+import kotlinx.coroutines.future.await
+import kotlinx.coroutines.runBlocking
+import org.koin.ktor.ext.inject
+import org.slf4j.LoggerFactory
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient
+import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
+import kotlin.reflect.KClass
+
+fun Application.migrateTables() {
+    val dynamoDbMigrationService: DynamoDbMigrationService by inject()
+    val dynamoDbClient: DynamoDbAsyncClient by inject()
+    val dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient by inject()
+
+    runBlocking {
+        dynamoDbMigrationService.createNecessaryTables(dynamoDbClient, dynamoDbEnhancedClient)
+    }
+}
+
+class DynamoDbMigrationService {
+    private val logger = LoggerFactory.getLogger(Application::class.java)
+
+    suspend fun createNecessaryTables(
+        dynamoDbClient: DynamoDbAsyncClient,
+        dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient
+    ) {
+        val existingTables = dynamoDbClient.listTables().await().tableNames().toList()
+
+        listOf(PlayerEntity::class).forEach {
+            createTableIfNotExists(existingTables, it, dynamoDbEnhancedClient)
+        }
+    }
+
+
+    private suspend fun <T : Any> createTableIfNotExists(
+        existingTables: List<String>,
+        item: KClass<T>,
+        dynamoDbEnhancedClient: DynamoDbEnhancedAsyncClient
+    ) {
+        val tableSchema = DataClassTableSchema(item)
+        if (existingTables.contains(item.simpleName)) {
+            logger.info("Table '${item.simpleName}' already exists.")
+        } else {
+            dynamoDbEnhancedClient.table(item.simpleName, tableSchema).createTable().await()
+            logger.info("Table '${item.simpleName}' created successfully.")
+        }
+    }
+}
+
diff --git a/src/main/kotlin/configuration/InjectionConfiguration.kt b/src/main/kotlin/configuration/InjectionConfiguration.kt
index 4b623254b5cc0c60c770546bce811e5ffcb3a83f..e1e4d5d3677ac90510bd6d76d6b2e581ecf4b9bf 100644
--- a/src/main/kotlin/configuration/InjectionConfiguration.kt
+++ b/src/main/kotlin/configuration/InjectionConfiguration.kt
@@ -11,12 +11,17 @@ import org.koin.logger.slf4jLogger
 fun Application.configureKoin() {
     install(Koin) {
         slf4jLogger()
-        modules(playerModule)
+        modules(databaseModule, playerModule)
     }
 }
 
+val databaseModule = module {
+    single { DynamoDbConfiguration().createDynamoDbClient() }
+    single { DynamoDbConfiguration().createDataSource(get()) }
+    single { DynamoDbMigrationService() }
+}
+
 val playerModule = module {
-    single { DynamoDbConfiguration().dataSource() }
     single<PlayerRepository> { PlayerRepository(get()) }
     single<PlayerService> { PlayerServiceImpl(get()) }
 }
diff --git a/src/test/kotlin/BaseIntegrationTest.kt b/src/test/kotlin/BaseIntegrationTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..693ffe014a67441cf44c2e4bf1da88fe628d26a1
--- /dev/null
+++ b/src/test/kotlin/BaseIntegrationTest.kt
@@ -0,0 +1,29 @@
+import betclic.test.configuration.testDatabaseModule
+import betclic.test.initialize
+import betclic.test.module
+import io.ktor.server.testing.*
+import org.koin.core.context.loadKoinModules
+import org.koin.test.KoinTest
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
+
+abstract class BaseIntegrationTest : KoinTest {
+
+    protected val application = TestApplication {
+        application {
+            module()
+            // override Database module with testContainers
+            loadKoinModules(testDatabaseModule)
+            initialize()
+        }
+    }
+
+    @BeforeTest
+    fun setup() {
+    }
+
+    @AfterTest
+    fun tearDown() {
+        TestDynamoDbConfiguration.localStack.stop()
+    }
+}
diff --git a/src/test/kotlin/TestDynamoDbConfiguration.kt b/src/test/kotlin/TestDynamoDbConfiguration.kt
new file mode 100644
index 0000000000000000000000000000000000000000..c524e9b161931cd5039397f71f93c6423901fc66
--- /dev/null
+++ b/src/test/kotlin/TestDynamoDbConfiguration.kt
@@ -0,0 +1,39 @@
+import org.slf4j.LoggerFactory
+import org.testcontainers.containers.localstack.LocalStackContainer
+import org.testcontainers.utility.DockerImageName
+import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
+import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient
+import software.amazon.awssdk.regions.Region
+import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient
+
+
+object TestDynamoDbConfiguration {
+    private val logger = LoggerFactory.getLogger(TestDynamoDbConfiguration::class.java)
+
+    val localStack: LocalStackContainer = LocalStackContainer(DockerImageName.parse("localstack/localstack:latest"))
+        .withServices(LocalStackContainer.Service.DYNAMODB)
+
+    init {
+        logger.info("Starting LocalStack DynamoDB container for tests...")
+        localStack.start()
+    }
+
+    fun createDynamoDbClient(): DynamoDbAsyncClient {
+        val endpoint = localStack.getEndpointOverride(LocalStackContainer.Service.DYNAMODB)
+        val credentials = AwsBasicCredentials.create(localStack.accessKey, localStack.secretKey)
+
+        return DynamoDbAsyncClient.builder()
+            .endpointOverride(endpoint)
+            .credentialsProvider(StaticCredentialsProvider.create(credentials))
+            .region(Region.US_EAST_1)
+            .build()
+    }
+
+    fun createDataSource(dynamoDbAsyncClient: DynamoDbAsyncClient): DynamoDbEnhancedAsyncClient {
+        logger.info("Using test dynamo-db config")
+        return DynamoDbEnhancedAsyncClient.builder()
+            .dynamoDbClient(dynamoDbAsyncClient)
+            .build()
+    }
+}
diff --git a/src/test/kotlin/TestInjectionConfiguration.kt b/src/test/kotlin/TestInjectionConfiguration.kt
new file mode 100644
index 0000000000000000000000000000000000000000..94015583afb05a5cf74fae6a84e8d3569a7269bc
--- /dev/null
+++ b/src/test/kotlin/TestInjectionConfiguration.kt
@@ -0,0 +1,10 @@
+package betclic.test.configuration
+
+import TestDynamoDbConfiguration
+import org.koin.dsl.module
+
+val testDatabaseModule = module {
+    single { TestDynamoDbConfiguration.createDynamoDbClient() }
+    single { TestDynamoDbConfiguration.createDataSource(get()) }
+    single { DynamoDbMigrationService() }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/player/PlayerIntegrationTest.kt b/src/test/kotlin/player/PlayerIntegrationTest.kt
index 2aeb2638e07033c08b3837f34a95f4180a9c8960..1fa6f2ab2231ac93d41dfb1be97fb7f7e0e253a8 100644
--- a/src/test/kotlin/player/PlayerIntegrationTest.kt
+++ b/src/test/kotlin/player/PlayerIntegrationTest.kt
@@ -1,17 +1,33 @@
 package player
 
+import BaseIntegrationTest
+import betclic.test.player.PlayerRepository
 import io.ktor.client.request.*
 import io.ktor.http.*
 import io.ktor.server.testing.*
+import org.assertj.core.api.Assertions.assertThat
 import org.junit.Test
+import org.koin.test.inject
 import kotlin.test.assertEquals
 
-class PlayerIntegrationTest {
+
+private const val PLAYER_NAME = "Clement"
+
+class PlayerIntegrationTest : BaseIntegrationTest() {
+
+    private val playerRepository: PlayerRepository by inject()
+
     @Test
-    fun `When calling post player, should return created`() = testApplication {
-        assertEquals(HttpStatusCode.Created, client.post("/player") {
+    fun `When calling player creation, a player should be saved in DB`() = testApplication {
+        val response = application.client.post("/players") {
             header(HttpHeaders.ContentType, ContentType.Text.Plain)
-            setBody("Test d'intégration")
-        }.status)
+            setBody(PLAYER_NAME)
+        }
+
+        assertEquals(HttpStatusCode.Created, response.status)
+        val players = playerRepository.findAll()
+        assertThat(players).hasSize(1)
+        assertThat(players.first()).extracting("pseudo", "pointsNumber")
+            .containsExactly(PLAYER_NAME, 0)
     }
-}
\ No newline at end of file
+}
diff --git a/src/test/kotlin/player/PlayerServiceTest.kt b/src/test/kotlin/player/PlayerServiceTest.kt
index 8d630f0fffb42a72a5f2fdeb529df5f9b8cb58b5..9671150b8ac3ad4f52c0ccf7c5454fd355d3981e 100644
--- a/src/test/kotlin/player/PlayerServiceTest.kt
+++ b/src/test/kotlin/player/PlayerServiceTest.kt
@@ -18,7 +18,7 @@ class PlayerServiceTest {
     private val player1 = Player(pseudo = john)
 
     @Test
-    fun `should create a new player`() {
+    fun `should create a new player in database`() {
         coEvery { playerRepository.createNewPlayer(player1) } just runs
         runBlocking { playerService.createNewPlayer(john) }
         coVerify(exactly = 1) { playerRepository.createNewPlayer(player1) }