Hello there. I'm currently working on an Android m...
# plugin-development
f
Hello there. I'm currently working on an Android multi-module project. Among those 42 modules, some are pure Kotlin modules, some are regular android modules and there are also few android modules with flavors. This results in 3 different names for the tasks to execute unit tests: Kotlin modules have just
test
, most android modules have
testDebugUnitTest
and the modules with flavors have also the flavor name inside the task name, like
testStagingDebugUnitTest
. Our goal however is be able to run all existing unit tests in a CI environment using a single command, e.g.
runAllTest
. Additionally, since there are different source sets in some of the flavor android modules, we'd like to have an option to configure what tasks in a given module should be executed to cover all source sets. What would be the recommended way of approaching this topic, that would follow the best practices and work properly with configuration avoidance and configuration cache? In the thread I'm pasting an initial draft of the solution, which definitely can be improved (it uses
afterEvaluate
, which I'm aware is not recommended). There's a convention plugin to register
runAllTest
task, making it dependent on the selected test task name and a custom extension to allow a module define its desired task name.
Copy code
class RunAllTestsPlugin : Plugin<Project> {
    override fun apply(target: Project) = with(target) {
        val testVariantsExtension = extensions.create(
            ConfigureTestTaskExtension.EXTENSION_NAME,
            ConfigureTestTaskExtension::class,
        )

        afterEvaluate {
            val testTasks = testVariantsExtension.customTestTasksNames
                .ifEmpty { listOf(testVariantsExtension.defaultTestTaskName) }
                .map(tasks::named)

            tasks.register("runAllTests") {
                dependsOn(testTasks)
            }
        }
    }
}
Copy code
abstract class ConfigureTestTaskExtension {
    val defaultTestTaskName = "testDebugUnitTest"
    val customTestTasksNames = mutableListOf<String>()

    companion object {
        const val EXTENSION_NAME = "configureTestTask"
    }
}
Copy code
fun Project.configureTestTask(action: ConfigureTestTaskExtension.() -> Unit) {
    extensions.configure<ConfigureTestTaskExtension>(action)
}
and then in the
build.gradle
for modules with special needs:
Copy code
configureTestTask {
    customTestTasksNames += listOf("testStagingDebugUnitTest", "testLiveDebugUnitTest")
}
e
use https://developer.android.com/reference/tools/gradle-api/8.10/com/android/build/api/variant/HasUnitTestBuilder#enableUnitTest() in
androidComponents.beforeVariants
to control which unit tests will run, then
./gradlew test
will run them all
f
Thank you, it indeed seems to solve the issue. However it's marked as deprecated and marked for removal from AGP 9.0
v
Also, usually you run the lifecycle task
check
which runs tests and maybe also further verification tasks and each project can decide which tasks
check
depends on.
But you can of course also register that separate lifecycle task if you want to have one specifically for tests 🙂
a
Correct me if I'm wrong, but it seems to me that the downside of using
enableUnitTest
is that it will disable some tests completely, so they won't execute even if I wanted to, by running a specific variant's unit tests task explicitly
f
sorry @ephemient and thanks for clarification. The
LibraryVariantBuilder
implements both those interfaces and both of them have the same name for this property. By default, the one from
VariantBuilder
is referenced and that's why the warning appears.