2 min read
How To Clean Up Database Tables After Each Integration Test

Solution

Implementation

 class JpaDatabaseCleanerExtension : AfterEachCallback {

    private lateinit var tableNames: List<String>

    override fun afterEach(context: ExtensionContext?) {
        if (context == null) {
            throw IllegalStateException("No extension context found")
        }
        if (!this::tableNames.isInitialized) {
            SpringExtension.getApplicationContext(context).getBean(EntityManager::class.java)
                .also { entityManager -> entityManager.initTableNames() }
        }
        SpringExtension.getApplicationContext(context).getBean(DataSource::class.java)
            .also { dataSource ->
                dataSource.connection.use { connection ->
                    connection.prepareStatement("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate()
                    tableNames.forEach { name -> connection.prepareStatement("TRUNCATE TABLE $name").executeUpdate() }
                    connection.prepareStatement("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate()
                }
            }
    }

    private fun EntityManager.initTableNames() {
        tableNames = metamodel.managedTypes
            .mapNotNull { it.javaType.kotlin.findAnnotation<Table>() }
            .map { table -> table.name }
    }
}

Usage

@ExtendWith(JpaDatabaseCleanerExtension::class)
@AutoConfigureMockMvc
@SpringBootTest
class ArticleFavoriteIntegrationTest(
    @Autowired private val mockMvc: MockMvc,
) {
    @Test
    fun `when post get delete articles favorite expect return valid response`() {
	    // testcodes
    }
}

Reference

  1. Do not use transactional in tests
  2. Cleaning up database tables after each integration test method with spring boot 2 and kotlin
  3. Test case is not represents real applications transaction scope · Issue #33 · raeperd/realworld-springboot-kotlin
  4. How To Clean Your Database Between JUnit 5 Tests With Spring Boot | Kotlin Tutorial - YouTube