3

I'm trying to clean up a database used by my component tests after each one so it's blank for the next. To do this I've got something like the following:

@MicronautTest
class ExampleTest(
    private val entityManager: EntityManager
) : BehaviorSpec() {

    override fun afterEach(testCase: TestCase, result: TestResult) {
        entityManager.transaction.begin()
        entityManager.createQuery("delete from DeviceEntity").executeUpdate()
        ementityManagertransaction.commit()
        entityManager.clear()
    }
    
    /* test code */
}

However when I run this I get the following error:

Could not obtain transaction-synchronized Session for current thread
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at io.micronaut.transaction.hibernate5.MicronautSessionContext.currentSession(MicronautSessionContext.java:100)
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:479)
    at io.micronaut.configuration.hibernate.jpa.TransactionalSessionInterceptor.intercept(TransactionalSessionInterceptor.java:56)
    at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:82)
    at io.micronaut.configuration.hibernate.jpa.TransactionalSession$Intercepted.unwrap(Unknown Source)
    at uk.arqit.cloud.device.core.service.v1.services.component.example.ExampeTest.afterEach(IncrementRatchetSuccessTest.kt:56)
...

I've seen in other posts mentions of using @Transaction to decorate the method or getting an entity manager from the session factory but when using these the error is the same.

There's no issue with running this code in the init { ... } clause of my tests (i.e. where the test code is) and it works exactly as expected. But if I run it in afterEach it has an issue.

Can anyone offer some advice on how to resolve this?

Thanks!

4

1 回答 1

2

Found the solution, first add the SessionFactory to the constructor:

@MicronautTest
class ExampleTest(
    private val entityManager: EntityManager,
    private val sessionFactory: SessionFactory
) : BehaviorSpec() {
    
    afterEach(...) {
        ...
    }
}

In the afterEach method have the following:

    override fun afterEach(testCase: TestCase, result: TestResult) {
        val sesh = sessionFactory.openSession()
        val em = sesh.entityManagerFactory.createEntityManager()

        /* do whatever you want with 'em' */
    }

It's worth saying, you can also declare sesh and em in the class body so they're accessbile by all methods

于 2021-03-10T15:59:15.823 回答