Closed linggom closed 8 years ago
No. You just need to read the code to figure it out. It's because you're using Robolectric, which doesn't set a processName
on the serviceInfo
returned by PackageManager.getServiceInfo()
.
Instead, you can let your application class have a method that can be overridden in unit tests:
public class VideoApplication extends Application {
public void onCreate() {
super.onCreate();
if (!isInUnitTests()) {
LeakCanary.install(this);
}
}
protected boolean isInUnitTests() {
return false;
}
}
Then you just need to create a TestVideoApplication
in your test code and the same package, and Robolectric will automatically use that instead:
public class TestVideoApplication extends VideoApplication {
protected boolean isInUnitTests() {
return true;
}
}
TODO: Update README to mention Robolectric
You can also disable leakCanary for unit tests:
testCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
If your tests run in debug mode like mine, to disable LeakCanary you'll need your testCompile
declaration to be above debugCompile
:
// WORKS
androidTestCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
// DOESN'T WORK
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
androidTestCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
Ran into this issue today so thought I'd share in case anyone else is confused
Propose to close based on PR above
@ygnessin @shubhamchaudhary I don't recall: which one works by default on a new Android project, androidTestCompile
or testCompile
? I'd like the README to mention the most standard one.
@pyricau I think testCompile
is for unit tests, which is probably the closest thing to "default" there is. I use androidTestCompile
for the test API that I wrote which runs on a device; probably less common. Sorry for the confusion!
thx!
@ygnessin This works for me in all of my projects:
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' // We only want leakcanary in debug builds
dogfoodCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // no-op
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // no-op
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // no-op
The readme now has this:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4'
}
So we can close this issue.
I'm seeing this NPE now in unit tests, that I've updated my environment (android gradle plugin 3.0.0)
I have this in my gradle file:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
androidTestImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
I tried changing the order of these statements, but so far haven't had luck getting rid of the NPE in unit tests, by trying to use the no-op version of the lib for tests.
Note: the same issue occurs if i keep the old testCompile
syntax instead of the new testImplementation
.
Note: tests run fine from within Android Studio. The error occurs running tests on the command line with ./gradlew clean testDebugUnitTest
Update: ok, if I RTFM and create a test application class, and override the setupLeakCanary()
as described, the tests now work on the command line. :)
However, it would be nice to just not use leak canary in tests by using the no-op
version of the lib.
As per @JakeWharton's #907 PR, it suggests to do the following without subclassing Application
(win!):
Taken from README.md
To disable LeakCanary in unit tests, add the following to your build.gradle:
// Ensure the no-op dependency is always used in JVM tests. configurations.all { config -> if (config.name.contains('UnitTest')) { 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) } } } }
@Kisty Thanks for the answer! it works :)
Adding @JakeWharton's suggestion still causes NPEs in my setup. I added the config lines after the dependencies block in my app module's build.gradle, as well as adding the no-op version directly using testImplementation
.
Using Gradle 4.6, Leak Canary 1.5.4, Android Studio 3.1.2 on High Sierra and Robolectric 3.8.
java.lang.NullPointerException
at com.squareup.leakcanary.internal.LeakCanaryInternals.isInServiceProcess(LeakCanaryInternals.java:112)
at com.squareup.leakcanary.LeakCanary.isInAnalyzerProcess(LeakCanary.java:145)
...
@Gloix can you post your dependency configuration with just the leak canary dependencies + the snippet Jake posted? Perhaps somethings in the wrong order.
@Kisty Nevermind. After a couple of rebuilds it is working now :D, but thanks anyway.
@Kisty I don't know what happened yesterday but my setup failed again, but this time I went deeper and pinpointed the set of possible configurations my test is running on:
prodDebugCompile, prodDebugApk, prodDebugProvided, prodDebugApi, prodDebugImplementation, prodDebugRuntimeOnly, prodDebugCompileOnly, prodDebugWearApp, prodDebugAnnotationProcessor, prodDebugCompileClasspath, prodDebugAnnotationProcessorClasspath, prodDebugRuntimeClasspath, prodDebugWearBundling, prodDebugBundleElements, prodDebugRuntimeElements, prodDebugApiElements, prodDebugMetadataElements
none of them contains the substring AndroidTest or UnitTest, but all of them contain the substring prodDebug. It seems my tests are not running with a test-like gradle config and I'm kind of lost as to what I can do to tell Android Studio to run my tests using a test-like gradle config.
@Gloix Were you ever able to resolve this? Adding the configurations block fixed it for me, but only for running from the command line. If I run tests from within the IDE, it still doesn't use the no-op artifact, and the tests fail.
@kschults I never tried running it through the command line. I fixed it by killing leakcanary until I need it again.
@Kisty Here's a shortened version of my build.gradle
. This version works fine when running from the command line ./gradlew :app:test<build type + flavor>UnitTest
, but not when running from the buttons in the IDE.
buildscript { ... }
configurations.all { config ->
// Ensure the no-op leak canary dependency is always used in 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)
}
}
}
}
...
android { ... }
dependencies {
...
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
qaImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}
Overriding my application in test works, but it would definitely be better if I could just use the no-op version. I've looked at the dependency graph generated by ./gradlew :app:dependences
, and it looks like it should be using the no-op version, but when I run it, it still uses the full artifact.
Try swapping the dependency line for test
and debug
so that the test
dependency comes after debug
. I wonder if the debug line is overwriting the test dependency. It's worth a try.
No luck. Same issue
Ok, how about trying the Canary build of Android Studio (download and install separately http://d.android.com/studio/preview). I know the team are aware of unit test issues in Android Studio 3.1 with Robolectric. Do you have Robolectric in unit tests?
Yeah, it's Robolectric. I'll give that a try (probably tomorrow) and get back to you
@Kisty Unfortunately, I'm getting the same results on the Canary build (3.2 Beta 1)
It is still the same issue in Android Studio 3.3 Canary 5
@Kisty Here's a shortened version of my
build.gradle
. This version works fine when running from the command line./gradlew :app:test<build type + flavor>UnitTest
, but not when running from the buttons in the IDE.buildscript { ... } configurations.all { config -> // Ensure the no-op leak canary dependency is always used in 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) } } } } ... android { ... } dependencies { ... testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4' qaImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' }
Overriding my application in test works, but it would definitely be better if I could just use the no-op version. I've looked at the dependency graph generated by
./gradlew :app:dependences
, and it looks like it should be using the no-op version, but when I run it, it still uses the full artifact.
Having the same issues when upgrading from version 1.6.1. When I use 1.6.2 or 1.6.3 I get the NPE, and when debugging seems to be using the full artifact and not the no-op
ones. This happens using Robolectric 4.0.1 and 4.2.1 (latests available to date).
OK, perhaps it's favouring the debug
artefact over the test
one for testDebug
. Have you tried:
testDebugImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
@Kisty same result.
I ran the test in console with ./gradlew test
and they run just fine but not on Android Studio. If I downgrade to version 1.6.1 they can run on Android Studio too.
@mikehc Sounds like the classpath resolution is different on AS from Gradle. Tried editing the run config so it uses JAR manifest or something else?
Another few things to try from Android Studio:
Build->Clean Project
then Build->Make project
(try doing two separate actions because I've had files locked and thus doesn't do a complete clean)File->Invalidate cache and restart
Tried editing the run config so it uses JAR manifest
@Kisty Can you give me some pointers of how to do that?
@mikehc
Edit configurations
Java 1.8 JRE
not Android API...
Shorten command line
and try running again.
I was wrong probably :)
Hi.
I got NPE when i run test using Unit Test build variants. Do you have any best practice to do this ?
Is it caused by multiple flavour on release ?