I'm trying to create a custom AndroidJUnitRunner that can be reused by multiple Android Library modules in my project for my Hilt Android tests so I don't have to keep creating a new one in each module.
I have a custom Android Library gradle config that is responsible for configuring everything related to Android.
android-library-config.gradle
:
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
// android related configuration
}
// additional configuration that should apply to ALL android library modules
Then, every Android Library module applies this gradle config instead of defining its own configuration:
some-feature-module/build.gradle
:
apply from: "$rootProject.projectDir/android-library-config.gradle"
android {
// additional setup if needed
}
dependencies {
implementation projects.someLibraryInThisProject
}
Following the Hilt testing documentation for instrumented tests:
To use the Hilt test application in instrumented tests, you need to configure a new test runner. This makes Hilt work for all of the instrumented tests in your project. Perform the following steps:
- Create a custom class that extends AndroidJUnitRunner in the androidTest folder.
- Override the newApplication function and pass in the name of the generated Hilt test application.
With the following example in the androidTest
directory:
// A custom runner to set up the instrumented application class for tests.
class CustomTestRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
}
}
Then, we need to configure the new test runner in our gradle file:
android {
defaultConfig {
// Replace com.example.android.dagger with your class path.
testInstrumentationRunner "com.example.android.dagger.CustomTestRunner"
}
}
However, I don't want to have to create a new CustomTestRunner
for every Android Library module in my project. Instead, I want to create one and reference it only in my android-library-config.gradle
so that it gets applied to each module that applies that config.
I've tried introducing a new Android Library module, :library:ui-testing:common
, and adding the custom test runner in its androidTest
directory:
library
└─ ui-testing
└─ common
└─ src
└─ androidTest
└─ java
└─ com.uitesting.common.CustomTestRunner
And then, updated my android-library-config.gradle
to reference this new test runner:
apply plugin: "com.android.library"
apply plugin: "kotlin-android"
android {
defaultConfig {
// Replace com.example.android.dagger with your class path.
testInstrumentationRunner "com.uitesting.common.CustomTestRunner"
}
}
dependencies {
implementation projects.library.uiTesting.common
}
Since :some-feature-module/build.gradle
applies android-library-config.gradle
I expect my Instrumented tests defined in this module to use this new custom test runner. Instead, my tests just don't run. I get the following output:
Starting 0 tests on Pixel 3 - 10
I've also tried having :some-feature-module
directly depend on :library:ui-testing:common
and adding the following to :some-feature-module/build.gradle
:
android {
defaultConfig {
// Replace com.example.android.dagger with your class path.
testInstrumentationRunner "com.uitesting.common.CustomTestRunner"
}
}
and same result.
I'm wondering if this is even possible since I haven't found any examples of this in the official Android Instrumented test documentation.
Seems like in order to make the custom instrumentation runner available for the build script to pick up is to place the runner in main/
instead of androidTest
of :ui-testing:common
.
Then your feature module that is going to use the test runner should depend on :ui-testing:common
directly as you described. (implementation(project("..."))
)
You can also see here that AndroidJunitRunner
is placed in java/...
and not javatests/...
.