Problem description
While system end-to-end tests are invoking methods annotated with @TransactionalEventListener
, I'm not able to invoke the same methods in narrower tests annotated with @MicronautTest
.
I've tested numerous variants with both injected EntityManager
and SessionFactory
. @MicronautTest(transactional = false)
is also tested. Calling JPA-method inside TestSvcWithTxMethod#someMethod
is also tested with same result. I've also tried tests without mocking TestAppEventListener
.
The below test/code yields
Verification failed: call 1 of 1: TestAppEventListener(#1).beforeCommit(any())) was not called. java.lang.AssertionError: Verification failed: call 1 of 1: TestAppEventListener(#1).beforeCommit(any())) was not called.
Calls to same mock: 1) TestAppEventListener(#1).hashCode()
Environment: Micronaut 3.7.5, Micronaut Data 3.9.3
Minimal reproducible code
Test is failing as well with transactional = false
import io.kotest.core.spec.style.BehaviorSpec
import io.micronaut.test.annotation.MockBean
import io.micronaut.test.extensions.kotest5.MicronautKotest5Extension.getMock
import io.micronaut.test.extensions.kotest5.annotation.MicronautTest
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.DefaultTestAppEventListener
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestAppEventListener
import no.mycompany.myapp.eventstore.services.appeventpublisher.testinfra.TestSvcWrapper
@MicronautTest
class AppEventWithBeforeCommitListenerMockTest(
testSvcWrapper: TestSvcWrapper,
testAppEventListener: TestAppEventListener
) : BehaviorSpec({
given("context with app event listener") {
`when`("calling someMethod") {
val mockBeforeCommitTestListener = getMock(testAppEventListener)
every { mockBeforeCommitTestListener.beforeCommit(any()) } answers {}
every { mockBeforeCommitTestListener.afterRollback(any()) } answers {}
testSvcWrapper.someMethod(message = "call #1")
verify { mockBeforeCommitTestListener.beforeCommit(any()) }
}
}
}) {
@MockBean(DefaultTestAppEventListener::class)
fun mockTestAppEventListener(): TestAppEventListener = mockk()
}
TestSvcWrapper
import jakarta.inject.Singleton
@Singleton
class TestSvcWrapper(
private val testSvcWithTxMethod: TestSvcWithTxMethod
) {
fun someMethod(message: String) {
testSvcWithTxMethod.someMethod(message)
}
}
TestSvcWithTxMethod
import io.micronaut.context.event.ApplicationEventPublisher
import jakarta.inject.Singleton
import javax.transaction.Transactional
@Singleton
open class TestSvcWithTxMethod(
private val eventPublisher: ApplicationEventPublisher<TestEvent>
) {
@Transactional(Transactional.TxType.REQUIRES_NEW)
open fun someMethod(message: String) {
eventPublisher.publishEvent(TestEvent(message))
}
}
TestEvent
import io.micronaut.core.annotation.Introspected
@Introspected
data class TestEvent(val message: String)
TestAppEventListener
interface TestAppEventListener {
fun beforeCommit(event: TestEvent)
fun afterRollback(event: TestEvent)
}
DefaultTestAppEventListener
import io.micronaut.transaction.annotation.TransactionalEventListener
import jakarta.inject.Singleton
import java.util.concurrent.atomic.AtomicInteger
@Singleton
open class DefaultTestAppEventListener : TestAppEventListener {
val receiveCount = AtomicInteger()
@TransactionalEventListener(TransactionalEventListener.TransactionPhase.BEFORE_COMMIT)
override fun beforeCommit(event: TestEvent) {
receiveCount.getAndIncrement()
}
@TransactionalEventListener(TransactionalEventListener.TransactionPhase.AFTER_ROLLBACK)
override fun afterRollback(event: TestEvent) {
receiveCount.getAndIncrement()
}
}