0

Let's say I have an app that depends on a library. This library has two methods:

  • void usedInApp()
  • void usedInTest()

In the app I call usedInApp(). I also have an instrumentation test that calls usedInTest(). If I run instrumentation tests ./gradlew app:connectedDebugAndroidTest is R8/AGP smart enough to know to keep usedInTest() or will it get removed?

tir38
  • 9,810
  • 10
  • 64
  • 107

1 Answers1

2

As usedInTest is not used by the app R8 will remove it, and when running your test it will fail with a MethodNotFouldError. So you need a keep rule to make sure usedInTest is still in the app when testing. One good way to do that is to add an annotation, e.g. KeepForTesting and annotate in the app what the tests need. And then add this keep rule:

-keep,allowobfuscation class * {
  @KeepForTesting *;
}

Note the allowobfuscation modifter. That allows these methods for testing to be renamed to shorter names. When Android Studio builds the tests it will automatically add an -applymapping option with the mapping file produced when building the app. This way the reference to usedInTest in the tests will be renamed to the actual method in the app after running R8.

For R8 itself we have automated that by analyzing the R8 tests to find what parts of R8, which are not on the public API, are used in the tests. From that we synthesize keep rules to keep this. Then we can run R8 on R8, and then run all tests on that version of R8 - which is also the version we ultimately ship.

sgjesse
  • 3,793
  • 14
  • 17