Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
* Adds a Java agent that sets a defaultUncaughtExceptionHandler for all jvm test modules,
* to ensure that exceptions thrown in Rx subscriptions (and coroutines?) aren't lost.
* Usually, one would do this with a JUnit RunListener, but Gradle doesn't support JUnit
* RunListeners, see
* This workaround adds a test dependency for all modules to the module containing the uncaught
* exception handler. This module contains a Java agent, which is called before JUnit runs. To
* setup the agent we compile the jar and add the filepath as JVM argument.
String defaultExceptionHandlerPath = ':path:to:java-agent:module'
Provider<Jar> jarTask
subprojects {
afterEvaluate { Project subproject ->
if (subproject.path == defaultExceptionHandlerPath) {
subproject.afterEvaluate {
jarTask = subproject.tasks.named('jar')
} else {
boolean isRealProject = project.plugins.hasPlugin('java') ||
project.plugins.hasPlugin('java-library') ||
project.plugins.hasPlugin('') ||
// Add the dependency only if one of the plugins is applied.
if (isRealProject) {
dependencies {
testImplementation project(defaultExceptionHandlerPath)
subproject.tasks.withType(Test).configureEach {
doFirst {
jvmArgs "-javaagent:${jarTask.get().archiveFile.get().asFile}"
Copy link

jameswald commented Nov 27, 2019

This works for Android modules with Gradle test execution:

android {
  testOptions {
    unitTests {
      all {
        // Android Studio doesn't apply jvmArgs. The agent will only be used in CI.
        jvmArgs "-javaagent:${project(':test:agent').jar.archivePath}"

Android Studio fails to pick up jvmArgs either way. 😢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment