¿Cómo ejecutar la prueba de Gradle cuando todas las pruebas están ACTUALIZADAS?

131

Tengo mi guión de calificación configurado. Cuando ejecuto la compilación de Gradle, todo funciona y ejecuta las pruebas de jUnit.

Después de eso, cuando ejecuto la prueba de Gradle, obtengo lo siguiente:

C:\Users\..\..\Project>gradle test
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE

Cuando realizo gradle clean, la construcción de Gradle funciona, por supuesto ... Quiero poder restablecer solo las pruebas, no construir todo el proyecto: ¿cómo debo hacer esto?

USer22999299
fuente
3
Esto parece innecesario, basado en la información dada. Si ni el código de la aplicación ni el código de prueba han cambiado, ¿por qué necesita volver a ejecutar las pruebas?
Jolta
10
@Jolta Algunas de las pruebas en mi código están relacionadas con entradas de 3 partes, estoy ejecutando mis pruebas no solo para asegurarme de que no puse ningún error dentro del código, sino también para verificar si algo cambia en las entradas de 3 partes que estoy recibiendo
USer22999299
44
Lamento ser quisquilloso, pero realmente no creo que esta sea la forma correcta de pensar sobre esto: si tiene entradas variables de 3 partes, ¿no es la forma correcta de lidiar con esto para burlarse de estas entradas de alguna manera? La prueba debería ser sobre probar el código que está escribiendo. ¿No estás en un peligro bastante obvio de obtener falsos positivos si confías en que los comentarios de terceros sean inaceptables? ¿No debería ser la estrategia para atender la entrada de problemas como parte del código de su aplicación?
Mike rodent
9
@mikerodent considera probar tu código con un servicio en línea de terceros. Desea supervisar los posibles cambios en la API del servicio para poder responder con las correcciones implementadas lo antes posible. ¿Las pruebas de CI no son una buena forma de hacerlo? Usar un simulacro solo le dirá que su propio código no tiene regresiones, pero las dependencias aún pueden tener cambios. el uso del servicio real indicaría que su producto realmente puede realizar las operaciones esperadas en el entorno actual.
Elist
55
Esto también es válido desde el punto de vista de la prueba de integración donde el punto de la prueba es validar la integración de su código con otros bits de código, donde no sería apropiado burlarse de las dependencias
1800 INFORMACIÓN

Respuestas:

172

Una opción sería usar la --rerun-tasksbandera en la línea de comando . Esto volvería a ejecutar toda la tarea de prueba y todas las tareas de las que depende.

Si solo está interesado en volver a ejecutar las pruebas, otra opción sería hacer que Gradle limpie los resultados de las pruebas antes de ejecutarlas. Esto se puede hacer usando la cleanTesttarea.

Algunos antecedentes: el complemento de Java define tareas limpias para cada una de las otras tareas. De acuerdo con la documentación :

cleanTaskName : elimina los archivos creados por la tarea especificada. cleanJar eliminará el archivo JAR creado por la tarea jar, y cleanTest eliminará los resultados de la prueba creados por la tarea de prueba.

Por lo tanto, todo lo que necesita para volver a ejecutar sus pruebas es también ejecutar la cleanTesttarea, es decir:
gradle cleanTest test

Amnon Shochot
fuente
3
gradle cleanTest testno vuelve a ejecutar las pruebas, limpia su salida, pero la testtarea aún obtendrá los resultados de la prueba de la memoria caché; consulte github.com/gradle/gradle/issues/9153
fue user2321368 el
3
El comentario de arriba es correcto. Pero si lo usa --no-build-cache, entonces funcionará como se esperaba, por ejemplo gradle cleanTest test --no-build-cache.
vRallev
51

Otra opción sería agregar lo siguiente en su build.gradle:

test.outputs.upToDateWhen {false}
František Hartman
fuente
1
Utilicé esta técnica para una funcTesttarea que creé para ejecutar pruebas funcionales.
Pharsicle
44
Este es un enfoque mucho mejor que la respuesta aceptada, ya que solo se aplicará a la tarea deseada. Se upToDateWhenpuede usar de cualquier forma "basada en código", como propiedades del sistema, variables de entorno, propiedades del proyecto, etc.
mkobit
1
Como menciona stackoverflow.com/a/52484259/340175 , hay una publicación de blog útil blog.gradle.org/stop-rerunning-tests que explica por qué este enfoque no se recomienda como un enfoque general. Sin embargo, estoy de acuerdo en que puede ser útil y logra lo que hace la pregunta.
JulianHarty
Sí, esta es una respuesta fechada, cuando escribí este Gradle estaba en la versión 2.11 y recién comenzó a ser utilizable, pero aún tenía muchos bordes ásperos, que se pulen hoy.
František Hartman
1
¡¡¡Gran respuesta!!! Pasó usando un parámetro: gradle test -Prerun-tests. Código en build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka
17

Este fue recientemente el tema en la publicación del blog de Gradle. Deje de volver a ejecutar sus pruebas . El autor muestra un ejemplo usando outputs.upToDateWhen { false }y explica por qué está mal:

Esto en realidad no fuerza repeticiones

Lo que el autor de este fragmento probablemente quiso decir es "Ejecutar siempre mis pruebas". Sin embargo, eso no es lo que hace este fragmento. Solo marcará la tarea desactualizada, lo que obligará a Gradle a recrear la salida. Pero aquí está la cosa, si la caché de compilación está habilitada, Gradle no necesita ejecutar la tarea para recrear la salida. Encontrará una entrada en el caché y descomprimirá el resultado en el directorio de salida de la prueba.

Lo mismo es cierto para este fragmento:

test.dependsOn cleanTest

Gradle desempaquetará los resultados de la prueba del caché de compilación después de que se haya limpiado la salida, por lo que no se volverá a ejecutar nada. En resumen, estos fragmentos están creando un no-op muy costoso.

Si ahora está pensando "Está bien, también desactivaré el caché", déjenme decirles por qué no deberían hacerlo.

Luego, el autor continúa explicando por qué volver a ejecutar algunas pruebas es una pérdida de tiempo:

La gran mayoría de sus pruebas deberían ser deterministas, es decir, dadas las mismas entradas, deberían producir el mismo resultado.

En los pocos casos en los que desea volver a ejecutar pruebas en las que el código no ha cambiado, debe modelarlas como entrada. Aquí hay dos ejemplos de la publicación del blog que muestran la adición de una entrada para que la tarea la use durante sus comprobaciones actualizadas.

task randomizedTest(type: Test) {
  systemProperty "random.testing.seed", new Random().nextInt()
}

task systemIntegrationTest(type: Test) {
  inputs.property "integration.date", LocalDate.now()
}

Recomiendo leer la publicación completa del blog.

mkobit
fuente
8
Esto suena muy bien para el caso de uso específico del que está hablando, pero estoy escribiendo pruebas posteriores a la implementación contra un servicio web externo en vivo y simplemente estoy usando junit y gradle para lograr esto. El código bajo prueba no se encuentra en el repositorio y, de hecho, no existe un 'código de aplicación' porque en realidad estoy probando un sistema de producción en vivo en lugar del código en sí. Gracias por la respuesta, ¡esto es muy útil! Solo quería señalar que hay casos de uso adicionales que requieren volver a ejecutar las pruebas cada vez, incluso si ninguno de los códigos que Gradle sabe está cambiando
Brandon
11

Aquí hay una solución que utiliza el archivo "build.gradle", en caso de que no desee modificar su línea de comando:

test {
    dependsOn 'cleanTest'
    //Your previous task details (if any)
}

Y aquí está la salida. Observe 2 cambios de su salida anterior:

1) Aparece una nueva tarea 'cleanTest' en la salida.

2) 'prueba' siempre se limpia (es decir, nunca 'ACTUALIZADO') por lo que se ejecuta cada vez:

$ gradle build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:jar
:bootRepackage
:assemble
:cleanTest
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test
:check
:build
TealSeed
fuente
1
ejecutar cleanTestantes testno volverá a ejecutar las pruebas, limpia su salida, pero la tarea de prueba aún obtendrá los resultados de la prueba de la memoria caché; consulte github.com/gradle/gradle/issues/9153
fue user2321368 el
8

--rerun-tasks funciona, pero es ineficiente ya que vuelve a ejecutar todas las tareas.

cleanTest por sí solo puede no ser suficiente debido a la caché de compilación.

Entonces, la mejor manera de lograr esto es:

./gradlew --no-build-cache cleanTest test
masc3d
fuente
0

Además, tener que agregar --rerun-taskses realmente redundante. Nunca sucede. Crea un --no-rerun-tasksy establece el --rerun-tasksvalor predeterminado cuandocleanTask

usuario1648995
fuente
-4

Creo que esta es una pregunta válida dado que en Gradle es posible ejecutar este comando test, ¡y lo que sucede es que no sucede nada!

Pero cuestionaría la necesidad de hacer esto, como dijo Jolta en su comentario: si ningún código ha cambiado, ¿por qué necesita volver a realizar la prueba? Si tiene dudas sobre la entrada de terceros, diría que debe tener esto en cuenta en el código de su aplicación. Si le preocupa que su código pueda ser "escamoso", es decir, capaz de pasar todas las pruebas la primera vez pero no una segunda (o la centésima vez), ¿no necesita pensar en por qué tiene estas dudas y abordarlas?

Personalmente, creo que este es un error de diseño (muy pequeño) en Gradle: si todo está completamente actualizado, en lugar de ir a "CONSTRUIR CON ÉXITO", debería decir "NO HAY CAMBIO DESDE LA ÚLTIMA CONSTRUCCIÓN EXITOSA: NADA HECHO".

Mike roedor
fuente
3
"¿No necesita pensar por qué tiene estas dudas y abordarlas?": Sí, pero para obtener datos en los que pensar, me gustaría ejecutar las pruebas varias veces y ver qué pasa. ¿Eso es tan loco?
mhsmith
1
@mikerodent Estoy parcialmente de acuerdo con su punto. Hay casos "fáciles", generalmente pruebas simples de unidades de caja blanca, en las que ningún cambio de código no significa nada realmente para volver a probar. Sin embargo, piense en las pruebas con dependencias. "Oh sí, Docker no estaba funcionando, etc." Hay pruebas en las que es la infraestructura (y en el desarrollo) quien configura las dependencias (se "proporcionan") y no la compilación. En estos casos, siempre quiero poder volver a ejecutar.
dbalakirev
@dbalakirev Sí, esto se me ocurrió ... pero ¿no deberías ser capaz de burlarte del papel de estas dependencias, como Docker ...? Quiero decir, si no estás haciendo eso, ¿no estás almacenando problemas futuros? No digo que esté 100% seguro, pero lo que digo es que sus pruebas deberían, en un mundo sin duda más ideal que el nuestro, cubrir todas las bases.
Mike roedor
Puede burlarse de sí, con el que tiene una dependencia (ventana acoplable) que si falla en usted significa que desea volver a ejecutar incluso si el código no cambió. Me gustaría enfatizar que este pensamiento no es para pruebas unitarias o pruebas en las que 1. intentas evitar las dependencias 2. o al menos te burlas de ellas usando el marco de prueba, sino cuando realmente están "provistas" si quieres.
dbalakirev
2
__ si ningún código ha cambiado, ¿por qué necesita volver a realizar la prueba? __ ¿Ha escuchado sobre las pruebas de integración?
Bogdan Mart