Skip to content

Latest commit

 

History

History
87 lines (63 loc) · 3.88 KB

recipes.md

File metadata and controls

87 lines (63 loc) · 3.88 KB

Recipes

Execution Listeners

The JUnit Platform supports execution listeners. Such listeners are useful for hooking into the test run. In fact, both IntelliJ IDEA and Gradle use those for their purposes — like showing a relevant UI or generating a report. We can use them as well.

  1. Declare the JUnit Platform Launcher dependency — this is where the TestExecutionListener is declared.

    testImplementation("org.junit.platform:junit-platform-launcher:{{JUnit Platform version}}")
  2. Declare the listener. For example, at src/test/kotlin/{{package path}}/Listener.kt.

    package {{package name}}
    
    class Listener : TestExecutionListener {
    
        override fun testPlanExecutionStarted(testPlan: TestPlan) {
            println("Hello there")
        }
    }
  3. Declare the listener at the ServiceLoader resource to let the JUnit Platform know about its existence. In our case it will be at src/test/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener.

    {{package name}}.Listener

That’s it. Take a look at the TestExecutionListener signature for different hooks. It is possible to declare multiple listeners via appending entries to the resource above.

Mockito Inline Mocks

Mockito has memory management issues when using the inline mock maker. As a consequence, it is necessary to clear mocks manually after each test. Let’s automate this.

class MockitoListener : TestExecutionListener {

    override fun executionFinished(testIdentifier: TestIdentifier, testExecutionResult: TestExecutionResult) {
        Mockito.framework().clearInlineMocks()
    }
}

RxJava Uncaught Exceptions

Uncaught RxJava 2+ exceptions will not fail tests. This happens because RxJava passes such exceptions to the UncaughtExceptionHandler instead of thowing them. The test engine doesn’t have a chance to record an exception and fail a test.

There is an interesting difference between platform UncaughtExceptionHandler implementations. The JVM one will print a stacktrace, the Android one will stop the process. This is fine but it is easy to expect that a test will fail on uncaught exceptions having an Android experience.

As a workaround, it is possible to use a custom UncaughtExceptionHandler.

class RxJavaListener : TestExecutionListener {

    override fun testPlanExecutionStarted(testPlan: TestPlan) {
        Thread.setDefaultUncaughtExceptionHandler { _, e ->
            throw AssertionError("Uncaught exception.", e)
        }
    }
}

Parallel Execution

The JUnit Jupiter engine supports parallel execution. The JUnit Platform provides APIs to make all engines parallel but it’s not so trivial, taking the nesting and the shared state into account. Plus it will not work well with the global-state-based tools like Mockito. Please open an issue describing the codebase and used testing tools and we’ll see what can be done in the future.

In the meanwhile, the Gradle parallel test execution is recommended.