Leakcanary: how to force opt out the leakCanary in the test with LeakCanary 2?

Created on 26 Aug 2019  路  10Comments  路  Source: square/leakcanary

https://square.github.io/leakcanary/upgrading-to-leakcanary-2.0/
says now it does not have leakcanary-android-no-op but only:

dependencies {
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-3'
}

in our app with 1.6.3 we have

//leakcanary
deps.leakcanary = "com.squareup.leakcanary:leakcanary-android:1.6.3"
deps.leakcanary_no_op = "com.squareup.leakcanary:leakcanary-android-no-op:1.6.3"

and would like to not run leakCanary in the test

configurations.all { config ->

    // Ensure the no-op dependency is always used in JVM tests.
    if (config.name.contains('UnitTest') || config.name.contains('AndroidTest')) {
        config.resolutionStrategy.eachDependency { details ->
            if (details.requested.group == 'com.squareup.leakcanary' && details.requested.name == 'leakcanary-android') {
                details.useTarget(group: details.requested.group, name: 'leakcanary-android-no-op', version: details.requested.version)
            }
        }
    }
}
dependencies {
    debugImplementation deps.leakcanary
    releaseImplementation deps.leakcanary_no_op
    testImplementation(deps.leakcanary_no_op) {
        force = true
    }
    androidTestImplementation(deps.leakcanary_no_op) {
        force = true
    }
}

now with LeakCanary 2, how to force opt out the leakCanary for the test?

documentation

Most helpful comment

Thanks 馃檹 . That's useful for people finding this issue. That being said, I want to automate this if possible so that LeakCanary keeps a minimal config and no one has to run into this.

All 10 comments

Have you tried this: https://square.github.io/leakcanary/recipes/#disabling-leakcanary ?

I guess you mean in the test code to call AppWatcher.config = AppWatcher.config.copy(enabled = false). It should work as long as the build is a debug build if the dependency is added as

dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-beta-3'
}

is there a way to do it in gradle for disabling leakCanary for all tests?

LeakCanary automatically disable itself if it detects the androidx.test.platform.app.InstrumentationRegistry class in the classpath (ie there's the AndroidX Espresso in the classpath, so I'm assuming you're not using that. You could run LeakCanary.config = LeakCanary.config.copy(dumpHeap = false) from within your test application class and that should disable leakcanary heap dumping.

As you pasted above, you maybe be able to remove the dependency from the config:

configurations.all { config ->

    // Ensure the no-op dependency is always used in JVM tests.
    if (config.name.contains('UnitTest') || config.name.contains('AndroidTest')) {
        config.resolutionStrategy.eachDependency { details ->
            if (details.requested.group == 'com.squareup.leakcanary') {
               // TODO Remove the dependency
               // Is there a way to do that?
            }
        }
    }
}

As @pyricau mentioned above, leakcanary disabled heapdump automatically when it detects instrumentation.

Further, the only way to find leaks is by explicitly attaching a listener to the instrumentation process, which could be done by adding :
-e listener leakcanary.FailTestOnLeakRunListener to the adb shell command, which I assume you are not doing.

@lannyf77 Not sure what exactly you're looking for, could you elaborate ?

We would like to disable leakcanary for all tests, and it could be done previously with the leakcanary-android-no-op.

Currently I have to put in different implementation of something like below within different build flavor:

for release:

object LeakCanaryObjectWatcher {
    fun watch(watchedObject: Any) {
        // NO-OP
    }
    fun enableLeakCanary(enable: Boolean = true) {
        // NO-OP
    }
}

for debug:

object LeakCanaryObjectWatcher {
    fun watch(watchedObject: Any) {
        AppWatcher.objectWatcher.watch(watchedObject)
    }

    fun enableLeakCanary(enable: Boolean = true) {
        AppWatcher.config = AppWatcher.config.copy(enabled = enable)
    }
}

and in the test, do something like:

override fun beforeActivityLaunched() {
            LeakCanaryObjectWatcher.enableLeakCanary(false)
        }

```

@lannyf77 can you confirm that you're running tests directly on Android devices, however you are not using espresso? What's the purpose of said tests?

@pyricau we do run test on real devices and with espresso, also for several submodules they have tests without ui such as for database; data model; middle tier etc. We would like to be able to run some flavor of test without leakCanary running.

Suggestion from @vRallev (based on our codebase) : we could look for "org.junit.Test" and disable leakcanary when found.

As a user you can do this and it is fairly easy (plus it's useful for many things)

android {
  defaultConfig {
    testBuildType "espresso"
  }
  buildTypes {
    espresso.initWith(debug)
  }
}

And then add leak canary to only debug builds. Your Espresso build will not even have Leak Canary to begin with.

Thanks 馃檹 . That's useful for people finding this issue. That being said, I want to automate this if possible so that LeakCanary keeps a minimal config and no one has to run into this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

divyenduz picture divyenduz  路  6Comments

vincent-paing picture vincent-paing  路  3Comments

SUPERCILEX picture SUPERCILEX  路  4Comments

matejdro picture matejdro  路  6Comments

arctouch-carlosottoboni picture arctouch-carlosottoboni  路  4Comments