4

My Android instrumentation tests need to modify / clear application data, therefore I want them to use a separate applicationId so that things like the private data directory and shared preferences are separated.

In the Android documentation, I read the following:

By default, the build tools apply an application ID to your instrumentation test APK using the application ID for the given build variant, appended with .test. For example, a test APK for the com.example.myapp.free build variant has the application ID com.example.myapp.free.test.

Although it shouldn't be necessary, you can change the application ID by defining the testApplicationId property in your defaultConfig or productFlavor block.

To test this, I created a fresh Android app using Android Studio 4.0.1. Here is the complete build.gradle:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "ch.dbrgn.myapplication"
        testApplicationId "ch.dbrgn.myapplication.test"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:rules:1.1.1'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

}

As you can see, I explicitly set testApplicationId to ch.dbrgn.myapplication.test.

To test that this works properly, I created an instrumentation test:

package ch.dbrgn.myapplication;

import android.content.Context;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;

@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void packageName() {
        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
        assertEquals("ch.dbrgn.myapplication", appContext.getPackageName());
    }

    @Test
    public void applicationId() {
        assertEquals("ch.dbrgn.myapplication.test", BuildConfig.APPLICATION_ID);
    }
}

The package should not have the .test suffix, but the application ID should.

However, this test fails:

ch.dbrgn.myapplication.ExampleInstrumentedTest > applicationId[MI 6 - 10] FAILED
    org.junit.ComparisonFailure: expected:<....dbrgn.myapplication[.test]> but was:<....dbrgn.myapplication[]>
    at org.junit.Assert.assertEquals(Assert.java:115)

How can I ensure that my instrumentation tests run in a separate app with its own completely separate data?

Danilo Bargen
  • 18,626
  • 15
  • 91
  • 127

1 Answers1

4

So from this answer, you can see that actually when you are doing instrumentation tests, there are 2 apps being installed, one doing the instrumentation and then your app under test. This testApplicationId does not refer to the application id of the app under test, but of the app doing the instrumentation. (And if you would want to access that, you would have to use ch.dbrgn.myapplication.test.BuildConfig.APPLICATION_ID, but that won't help you).

So, to have a separate app id for the app under test when doing instrumentation tests, you would have to manually define an extra buildType and specify another applicationId there, and then use that for testing. Eg:

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        releaseUnderTest {
            initWith buildTypes.release
            applicationId "ch.dbrgn.myapplication.undertest"
        }
    }
francis duvivier
  • 2,056
  • 11
  • 17
  • Thanks for that eye opener. It explains the issues I had while debugging, because I had the wrong conceptual model. (And I must say, the docs do a terrible job explaining this...) Thanks also for pointing out "initWith" to extend an existing build type, I wasn't aware that this exists! – Danilo Bargen Aug 31 '20 at 21:16