1

I have a Kotlin project, using JDK 17, Junit 5.10.0, and junit-platform 1.10.0 (the latest Junit versions as of today) with several thousands of unit tests.

Because of some framework choices we made, we are forced to run tests in sequential mode: namely, we use Exposed, which is not easy to mock. Some of our services in which we inject DAOs use Exposed transactions, which we are forced to mock - injecting mock DAOs is not enough. Exposed uses some static calls, so we had to introduce Mockk just for the purpose of mocking these. The tests that need transactions to be mocked have a special tag, that a custom BeforeEachCallback / AfterEachCallbackextension sees and configures the mock accordingly.

private fun mockExposedTransaction() {
    val database = mockk<Database>()
    val datasource = mockk<DataSource>()
    val transaction = mockk<Transaction>()
    val transactionManager = mockk<TransactionManager>()

    mockkObject(Database)
    every { Database.connect(datasource) } answers { database }

    mockkObject(TransactionManager)
    every { TransactionManager.resetCurrent(any()) } answers {}
    every { TransactionManager.currentOrNull() } answers { transaction }
    every { TransactionManager.managerFor(any()) } answers { transactionManager }

    every { transactionManager.currentOrNull() } answers { transaction }
    every { transactionManager.defaultIsolationLevel } answers { 0 }
    every { transactionManager.defaultRepetitionAttempts } answers { 0 }
    every { transactionManager.bindTransactionToThread(eq(transaction)) } answers { }
    every { transactionManager.newTransaction(eq(0), eq(transaction)) } answers { transaction }

    every { transaction.db } answers { database }
    every { database.useNestedTransactions } answers { false }
}

This works OK, but only in sequential mode. When running those tests with @Execution(ExecutionMode.CONCURRENT), then Mockk gets confused mixing the mocks between different threads, as mockkObject is not threadsafe. That's the way it is, and we accept it.

our junit-platform.properties currently has junit.jupiter.execution.parallel.enabled as false, but we would like to change that and enable concurrent mode on some individual tests, as we have tests that don't target objects that use Exposed. That's what Junit documentation recommends :

Please note that enabling this property is only the first step required to execute tests in parallel. If enabled, test classes and methods will still be executed sequentially by default. Whether or not a node in the test tree is executed concurrently is controlled by its execution mode.

so I am switching junit.jupiter.execution.parallel.enabled to true: running the tests, it's passing - normal.

Then, I am adding @Execution(ExecutionMode.CONCURRENT) on a simple test that does NOT need transaction mocking.

The test methods on this test run in parallel and are all passing (as expected), but surprisingly, another unrelated test that needs transaction mocking, fails, with an error suggesting that the Exposed mocks haven't been properly set up (yet ?) :

Please call Database.connect() before using this code

When I run this test individually, it passes.

So I am confused because that's not what I expect from reading the documentation: my understanding is that only the test annotated with @Execution(ExecutionMode.CONCURRENT) should run in parallel, the rest of the tests should not be impacted at all. But it doesn't seem it's the case, as I observe unexpected side effects as soon as there's one test with ExecutionMode.CONCURRENT.

Any idea of what could happen? should I open a bug on the Junit5 side?

Aqib Chattha
  • 197
  • 11
Vincent F
  • 6,523
  • 7
  • 37
  • 79

0 Answers0