android - studio - Cómo cambiar/cambiar testInstrumentationRunner dinámicamente con gradle
settings gradle android studio (4)
Mi proyecto tiene 2 grupos diferentes de pruebas. Un grupo solo se ejecuta con AndroidJUnitRunner
predeterminado, el otro tiene que ejecutarse con una implementación personalizada. TestRunner extends MonitoringInstrumentation
.
Actualmente cambio el testInstrumentationRunner
editando build.gradle
cada vez que necesito ejecutar el otro grupo de pruebas:
android{
defaultConfig {
//testInstrumentationRunner "my.custom.TestRunner"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
Sé que los sabores pueden tener su propio testInstrumentationRunner
pero mi aplicación actual ya tiene 2 flavourDimensions
. Usar sabores en realidad tiene la intención de tener diferentes versiones de una aplicación. Necesito 2 versiones de la aplicación de prueba, ambas probando la misma aplicación con diferentes testInstrumentationRunner
s.
Traté de cambiar el testInstrumentationRunner
iterando sobre todas las variantes de prueba. En realidad, hay múltiples propiedades testInstrumentationRunner
:
android.testVariants.all { TestVariant variant ->
//readonly
variant.variantData.variantConfiguration.instrumentationRunner
variant.variantData.variantConfiguration.defaultConfig.testInstrumentationRunner
}
Pero tan pronto como se llama a android.testVariants
la compilación se configura y todos los cambios no se reflejan en la compilación.
¿Cómo puedo cambiar el testInstrumentationRunner (desde un plugin de Gradle) dinámicamente?
Preferiría tener 2 tareas diferentes de gradle, cada una usando un testInstrumentationRunner
diferente pero probando la misma variante. Como intento crear un plugin de gradle, la solución también debería funcionar como plugin.
Tuve un problema similar, utilicé el gramaje de tarea de Gradle. Según su declaración "Mi proyecto tiene 2 grupos diferentes de pruebas". Asumiré que tiene definidas diferentes tareas, las llamaré testGroupOne y testGroupTwo:
task testGroupOne{
}
task testGroupTwo{
}
gradle.taskGraph.whenReady {taskGraph ->
if(taskGraph.hasTask(testGroupOne)){
testInstrumentationRunner "my.custom.TestRunner"
} else if (taskGraph.hasTask(testGroupTwo)){
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
Esto le permite establecer el valor de testInstrumentationRunner después de la configuración, pero antes de la ejecución.
Esta es una solución parcial, pero tal vez esto hará que las cosas sean menos engorrosas para usted: no le permite ejecutar las pruebas con ambos corredores de prueba en la misma versión. Si lo desea, debe clonar todas las instancias de tarea de DeviceProviderInstrumentTestTask
, que, en mi opinión, es demasiado compleja y frágil.
Esto funciona para mí (Gradle 2.4 y Android build tools 1.2.3). Utiliza API internas, por lo que es posible que esto ya no funcione con la próxima versión de las herramientas de compilación de Android.
Debe modificar las tareas generadas por el complemento de Android una vez que se haya evaluado el proyecto. Los cambios serán luego utilizados por las tareas de prueba. La propiedad que realmente cambia el corredor de prueba utilizado es task.testVariantData.variantConfiguration.testedConfig.mergedFlavor.testInstrumentationRunner
. En lugar de realizar estos cambios durante la fase de configuración (es decir, fuera de una tarea), los cambios se aplican con una tarea, por lo que el corredor de prueba solo se utiliza cuando se solicita. Al forzar que las tareas de prueba se ejecuten después de useMyTestRunner
(si este último es parte de la compilación), el nombre de la clase del useMyTestRunner
de prueba se habrá cambiado cuando se inicie una tarea de prueba:
project.afterEvaluate {
task useMyTestRunner << {
tasks.withType(com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask.class) { task ->
task.testVariantData.variantConfiguration.testedConfig.mergedFlavor.testInstrumentationRunner = ''com.mycompany.MyTestRunner''
}
}
tasks.withType(com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask.class) { task ->
task.mustRunAfter useMyTestRunner
}
}
Ahora puede ejecutar las pruebas utilizando el corredor de prueba predeterminado configurado para el sabor (es) con:
gradle :myApp:connectedAndroidTest
Cuando desee ejecutar las pruebas con su corredor de prueba, use:
gradle :myApp:connectedAndroidTest :myApp:useMyTestRunner
No task.testVariantData.variantConfiguration.testedConfig.mergedFlavor.testInstrumentationRunner
cheques para null
para ninguna de las propiedades recuperadas usando task.testVariantData.variantConfiguration.testedConfig.mergedFlavor.testInstrumentationRunner
. Debe agregarlos para mayor robustez. Creo que al menos testedConfig
necesita atención. Consulte getInstrumentationRunner()
en https://android.googlesource.com/platform/tools/build/+/master/builder/src/main/java/com/android/builder/VariantConfiguration.java
Puede usar una importación para com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
en la parte superior de su archivo de compilación, por lo que solo debe usar el nombre simple de la clase.
¿Ha considerado usar el parámetro de la consola como un interruptor entre dos configuraciones? Tan sencillo como eso:
android {
defaultConfig {
if (project.ext.has("customRunner")) {
testInstrumentationRunner "my.custom.TestRunner"
} else {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
}
Y luego, por ejemplo, ejecute gradlew aDeb -PcustomRunner
si desea probar utilizando un corredor personalizado o gradlew aDeb
para usar el valor predeterminado.
Sé que no es ciencia espacial, pero lo más simple es mejor, ¿no? También puedes usarlo en tu complemento, solo obtén el objeto Project y haz algo similar.
Desde el complemento android gradle 1.3 es posible crear módulos de prueba separados. Cada uno de esos módulos de prueba puede tener su propio testInstrumentationRunner.
Para ver un ejemplo detallado, consulte el proyecto de ejemplo AndroidTestingBlueprint en github.
La solución de @ johan-stuyts que obtuvo recompensa funciona bien (o al menos lo hizo con el complemento Android gradle 1.2). Pero usa API privadas y crear un módulo separado es más fácil y a prueba de futuro.