12

If I:

  • Create a brand-new Android Studio 3.5.1 project (Kotlin, API 21, "Empty Activity" template)
  • Run the app from inside the IDE
  • Confirm the app is installed and has a launcher icon
  • Run the connectedAndroidDebugTest Gradle task (from inside Android Studio or via gradlew)

The app winds up being uninstalled by the test run. I get that behavior even if I add a testApplicationId value to defaultConfig to have the test code use a different application ID.

How do I stop that behavior? How can I run instrumented tests from the command line, without disturbing an existing app installation?

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 2
    Similar to this https://stackoverflow.com/questions/47670066/run-connectedandroidtest-and-skip-uninstall (they didn't get a solution, just some workarounds) – Tyler V Nov 03 '19 at 19:44
  • @TylerV: The thing is, I swear it didn't do this a year ago. I use a Gradle task for a unified coverage report (merging the output of instrumented tests and unit tests). I was using that on a project a year ago, and I do not remember running into this problem. I just implemented the report again on a new project, and now I'm seeing the uninstall issue. It's possible that my memory of what happened a year ago is fuzzy, but uninstalling an app that requires authentication is annoying, so I would like to think that I'd remember it. – CommonsWare Nov 03 '19 at 19:56
  • If I right click on an individual test file and run it that way, it also doesn't uninstall the app when done (I do this sometimes to load up some pre-populated data in the app). It's probably an added step in the connected test task... – Tyler V Nov 03 '19 at 20:10

4 Answers4

3

Maybe try to run it via adb like this:

adb shell am instrument -w com.android.demo.app.tests/android.support.test.runner.AndroidJUnitRunner

It will not uninstall your app.

here it is described in more details.

Pavlo Ostasha
  • 14,527
  • 11
  • 35
  • 1
    That might be practical in some situations. In my case, the task that I really want to execute is `createDebugCoverageReport`, which depends upon `connectedAndroidDebugTest`. So, I cannot avoid `connectedAndroidDebugTest`, short of somehow rewriting the `createDebugCoverageReport`. – CommonsWare Nov 04 '19 at 14:39
  • In the link to the official documentation I provided in the answer there is a [list](https://developer.android.com/studio/test/command-line#AMOptionsSyntax) of possible adb `am instrument` command options you can use with `am instrument`. And you can run a coverage report via adb with the help of `emma` option set to `true`. Also you can change a destination file of the coverage report with the help of `coverageFile ` option. Hope it helps. – Pavlo Ostasha Nov 07 '19 at 11:12
  • "And you can run a coverage report via adb with the help of emma option set to true." -- AFAIK, Android has not used emma coverage for years, having switched long ago to Jacoco. I suppose they could have kept the option name the same while changing the implementation... – CommonsWare Nov 07 '19 at 12:01
  • Maybe - I don't know the details. But there is such possibility. – Pavlo Ostasha Nov 07 '19 at 12:05
3

The connectedCheck task has the type DeviceProviderInstrumentTestTask. For a simple test run on one device it uses a SimpleTestRunner, which in turn uses a SimpleTestRunnable to actually execute the test. Here you find a structure of

try {
    // connect to device
    // install all APKs
    // run tests
} catch(Exception e) {
    // handle error
} finally {
    // get test report
    // uninstall all APKs
    // disconnect from device
}

I'm not perfectly sure if I've found the most recent implementations, but this exact behavior dates back several years. So I guess you can't achieve what you're asking for.

tynn
  • 38,113
  • 8
  • 108
  • 143
  • Because the link is broken I think the `SimpleTestRunnable` is called `SimpleTestCallable` now: https://android.googlesource.com/platform/tools/base/+/8d969614b7beca74e4d17f2d1c5956e75053f7ce/build-system/builder/src/main/java/com/android/builder/internal/testing/SimpleTestCallable.java – Bruno Bieri Jan 05 '21 at 18:09
3

I just ran into this issue and discovered at least one thing that can cause it is the version of Android Gradle Plugin being used.

  • AGP 7.4.1 -> Does not uninstall the app after test completes
  • AGP 8.1.0 -> Uninstalls the app after test completes

Unsure what the behavior is for other versions. Would be nice to know how to tell AGP 8.1.0 not to uninstall the app.

Kevin Worth
  • 421
  • 4
  • 15
2

The instrumentation installs 2 APKs: the APK under test and the APK with the test code.

It also uninstalls both APKs before it tries to install the new ones and I don't know if it's possible to prevent the uninstall itself.

testApplicationId changes only application id for the APK with the test code (which is normally the same as for the main APK with ".test" appended) the application id of the APK under test remains still the same. But it is possible to create separate buildType for the APK under test (with exactly the same configuration as the debug build type) and use that.

Then connectedAndroidXYZTest could be used to run the tests (or createXYZCoverageReport).

Josef Adamcik
  • 5,620
  • 3
  • 36
  • 42
  • 1
    I am accepting tynn's answer, because it is the most accurate one for the question. I am giving you the bounty for the safest workaround... assuming your code does not try doing anything at runtime based on build type. If it does, you will need to remember to keep the `XYZ` build type in mind with that code. – CommonsWare Nov 07 '19 at 22:28
  • @CoommonsWare that is correct. I usually avoid checks for build type directly and use a "buildConfigField" directive in gradle to generate boolean flags (or whatever suits the problem) in the `BuildConfig` class. – Josef Adamcik Nov 08 '19 at 08:33