JUnit Spring extension

Writing a plain JUnit extension is quite a straightforward task and it is described well in user-guide. It gets a bit more complicated when we try to inject Spring components into the integration testing context.

Let's try to clean up embedded Elasticsearch indexes before every integration test:

class ElasticsearchCleanerExtension : BeforeEachCallback {

    override fun beforeEach(context: ExtensionContext) {
        val contextManager = testContextManager(context)
        val applicationContext = contextManager.testContext.applicationContext as GenericApplicationContext
        val cleaner = applicationContext.getBean(ElasticsearchCleaner::class.java)
        cleaner.cleanup()
    }

    private fun testContextManager(context: ExtensionContext):TestContextManager {
        val namespace = Namespace.create(SpringExtension::class.java)
        val store = context.getStore(namespace)
        return store.getOrComputeIfAbsent(context.requiredTestClass, ::TestContextManager, TestContextManager::class.java)
    }
}

which depends on the actual clean up component:

@Component
class ElasticsearchCleaner(val studentRepository: StudentRepository) {
    fun cleanup() {
        studentRepository.deleteAll()
            .block(Duration.ofSeconds(2))
    }
}

Each test must be annotated:

@SpringBootTest
@ExtendWith(ElasticsearchCleanerExtension::class)
class StudentPersistenceTest {
....
}

Now, the student index will be cleaned up before each test in the StudentPersistenceTest class.