Como executar o teste Gradle quando todos os testes estão atualizados?

130

Eu tenho meu script de notas configurado. Quando executo a compilação Gradle, tudo está funcionando e ele executa os testes do jUnit.

Depois disso, quando executo o teste Gradle, recebo o seguinte:

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

Quando eu executo gradle clean, a construção do Gradle funciona, é claro ... Eu quero poder redefinir apenas os testes, não o projeto inteiro: como devo fazer isso?

USer22999299
fonte
3
Isso parece desnecessário, com base nas informações fornecidas. Se nem o código do aplicativo nem o código de teste foram alterados, por que você precisa executar novamente os testes?
Jolta
10
@Jolta Alguns dos testes no meu código estão relacionados a entradas de terceiros, estou executando meus testes não apenas para garantir que não coloquei nenhum bug dentro do código, mas também para verificar se alguma coisa muda nas entradas de terceiros O que eu estou recebendo é
USer22999299
4
Desculpe ser exigente, mas realmente não acho que essa seja a maneira correta de pensar sobre isso: se você tem entradas variáveis ​​de três partes, não é a maneira correta de lidar com isso para zombar dessas entradas de alguma maneira? Testar deve realmente ser sobre testar o código que você está escrevendo. Você não corre o risco óbvio de obter falso-positivos se depender de informações de terceiros para ser inaceitável? A estratégia não deveria ser a inserção de problemas como parte do código do seu aplicativo?
mike roedor
9
@mikerodent considere testar seu código em um serviço on-line de terceiros. Você deseja monitorar possíveis alterações na API de serviço para poder responder com correções implementadas o mais rápido possível. Os testes de CI não são uma boa maneira de fazer isso? Usar uma simulação simulará apenas que seu próprio código não tem regressões, mas as dependências ainda podem ter alterações. o uso do serviço real indicaria que seu produto pode realmente executar as operações esperadas no ambiente atual.
Elist
5
Isso também é válido a partir de um ponto de teste de integração de vista onde o ponto do teste é para validar a integração de seu código com outros pedaços de código, onde seria não apropriar-se para zombar em dependências
1800 INFORMAÇÃO

Respostas:

171

Uma opção seria usar o --rerun-taskssinalizador na linha de comando . Isso executaria novamente toda a tarefa de teste e todas as tarefas das quais depende.

Se você estiver interessado apenas em executar novamente os testes, outra opção seria fazer com que o gradle limpe os resultados dos testes antes de executá-los. Isso pode ser feito usando a cleanTesttarefa.

Alguns antecedentes - o plug-in Java define tarefas limpas para cada uma das outras tarefas. De acordo com a documentação :

cleanTaskName - Exclui os arquivos criados pela tarefa especificada. O cleanJar excluirá o arquivo JAR criado pela tarefa jar e o cleanTest excluirá os resultados do teste criados pela tarefa de teste.

Portanto, tudo o que você precisa para executar novamente seus testes é também executar a cleanTesttarefa, ou seja:
gradle cleanTest test

Amnon Shochot
fonte
3
gradle cleanTest testnão executa novamente os testes, limpa a saída, mas a testtarefa ainda obtém os resultados do cache - consulte github.com/gradle/gradle/issues/9153
dan.m foi user2321368
3
O comentário acima está correto. Mas se você usar --no-build-cache, funcionará como esperado, por exemplo gradle cleanTest test --no-build-cache.
vRallev 28/01
51

Outra opção seria adicionar o seguinte em seu build.gradle:

test.outputs.upToDateWhen {false}
František Hartman
fonte
1
Eu usei essa técnica para uma funcTesttarefa que criei para executar testes funcionais.
pharsicle 26/05
4
Essa é uma abordagem muito melhor do que a resposta aceita, pois será aplicada apenas à tarefa desejada. O upToDateWhenpode ser usado de qualquer maneira "code-driven", como propriedades do sistema, variáveis de ambiente propriedades do projeto, etc.
mkobit
1
Como menciona a resposta stackoverflow.com/a/52484259/340175 , há uma publicação útil no blog blog.gradle.org/stop-rerunning-tests, que explica por que essa abordagem não é recomendada como abordagem geral. Concordo, no entanto, que pode ser útil e alcançar o que a pergunta faz.
precisa saber é o seguinte
Sim, esta é uma resposta datada, quando escrevi este Gradle na versão 2.11 e comecei a ser utilizável, mas ainda tinha muitas arestas, hoje polidas.
František Hartman
1
Ótima resposta!!! Passou-lo usando um parâmetro: gradle test -Prerun-tests. Código no build.gradle:if(project.hasProperty("rerun-tests")) { test.outputs.upToDateWhen {false} }
AlikElzin-kilaka 13/11/19
17

Esse foi recentemente o tópico na postagem do blog de Gradle. Pare de executar novamente seus testes . O autor mostra um exemplo usando outputs.upToDateWhen { false }e explica por que está errado:

Na verdade, isso não força as reprises

O que o autor deste trecho provavelmente queria dizer é "Sempre execute novamente meus testes". Mas não é isso que esse trecho faz. Ele marcará apenas a tarefa desatualizada, forçando Gradle a recriar a saída. Mas eis o seguinte: se o cache de compilação estiver ativado, Gradle não precisará executar a tarefa para recriar a saída. Ele encontrará uma entrada no cache e descompacta o resultado no diretório de saída do teste.

O mesmo vale para este trecho:

test.dependsOn cleanTest

Gradle descompactará os resultados do teste do cache de compilação após a limpeza da saída, para que nada seja executado novamente. Em resumo, esses trechos estão criando um no-op muito caro.

Se agora você está pensando em "Ok, eu vou desativar o cache também", deixe-me dizer por que você não deveria.

Em seguida, o autor continua explicando por que executar novamente alguns testes é uma perda de tempo:

A grande maioria dos seus testes deve ser determinística, ou seja, dadas as mesmas entradas, eles devem produzir o mesmo resultado.

Nos poucos casos em que você deseja executar novamente os testes nos quais o código não foi alterado, você deve modelá-los como uma entrada. Aqui estão os dois exemplos da postagem do blog que mostram a adição de uma entrada para que a tarefa a use durante suas verificações atualizadas.

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

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

Eu recomendo a leitura de todo o post do blog.

mkobit
fonte
8
Isso parece ótimo para o caso de uso específico que você está falando, mas estou escrevendo testes pós-implantação em um serviço da web externo ativo e, por acaso, estou usando junit e gradle para fazer isso. O código em teste não está no repositório e, de fato, não existe um 'código de aplicativo' porque, na verdade, estou testando um sistema de produção ao vivo em vez do próprio código. Obrigado pela resposta, isso é muito útil! Só queria salientar que existem casos de uso adicionais que necessitam de executar novamente os testes de cada vez, mesmo se nenhum dos Gradle código conhece está mudando
Brandon
11

Aqui está uma solução usando o arquivo "build.gradle", caso você não queira modificar sua linha de comando:

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

E aqui está a saída. Observe 2 alterações em relação à saída anterior:

1) Uma nova tarefa 'cleanTest' aparece na saída.

2) 'teste' é sempre limpo (ou seja, nunca 'ATUALIZADO'), por isso é executado sempre:

$ 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
fonte
1
A execução cleanTestanterior testnão executará novamente os testes, mas limpará a saída, mas a tarefa de teste ainda obterá os resultados do cache - consulte github.com/gradle/gradle/issues/9153
dan.m foi user2321368
8

--rerun-tasks funciona, mas é ineficiente, pois executa novamente todas as tarefas.

cleanTest por si só pode não ser suficiente devido ao cache de compilação.

portanto, a melhor maneira de fazer isso é:

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

Além disso, ter que adicionar --rerun-tasksé realmente redundante. Isso nunca acontece. Crie um --no-rerun-taskse torne-o --rerun-taskspadrão quandocleanTask

user1648995
fonte
-1

TL; DR

test.dependsOn cleanTest
Topera
fonte
2
De acordo com o stackoverflow.com/a/52484259/466862 que não funcionará.
Mark Rotteveel
Bem, os documentos da Gradle são um pouco confusos ... Aqui eles dizem que o cleanTest pode ser usado para esse fim. docs.gradle.org/current/userguide/… . E também, ele funciona na minha máquina (e versão gradle 4.10.3);)
Topera
-4

Eu acho que essa é uma pergunta válida, uma vez que é possível em Gradle executar este comando test, e o que acontece é que nada acontece!

Mas eu questionaria a necessidade de fazer isso, como Jolta disse em seu comentário: se nenhum código foi alterado, por que você precisa testar novamente? Se você tiver dúvidas sobre a entrada de terceiros, eu diria que você precisa atender a isso no código do aplicativo. Se você tem medo de que seu código seja "esquisito", ou seja, capaz de passar em todos os testes pela primeira vez, mas não uma segunda (ou centésima vez), você não precisa pensar por que tem essas dúvidas e resolvê-las?

Pessoalmente, acho que isso é uma falha de design (muito menor) em Gradle: se tudo estiver completamente atualizado, em vez de se tornar "CONSTRUÍDO COM SUCESSO", deve dizer "SEM MUDANÇA DESDE O ÚLTIMO CONSTRUÇÃO COM SUCESSO: NADA FAZER".

microfone roedor
fonte
3
"você não precisa pensar por que tem essas dúvidas e resolvê-las?": Sim, mas para obter dados para pensar, eu gostaria de executar os testes algumas vezes e ver o que acontece. Isso é tão louco?
precisa saber é o seguinte
1
@mikerodent Concordo parcialmente com o seu ponto. Existem casos "fáceis", geralmente simples testes de unidade de caixa branca, em que nenhuma alteração de código significa realmente nada para re-testar. Pense em testes com dependências. "Oh sim, o docker não estava funcionando etc." Existem testes em que é a infraestrutura (e no dev você) quem configura as dependências (elas são "fornecidas") e não a compilação. Nestes casos, eu sempre quero poder executar novamente.
precisa saber é o seguinte
@dbalakirev Sim, isso me ocorreu ... mas você não deveria zombar do papel dessas dependências, como o Docker ...? Quero dizer, se você não está fazendo isso, não está armazenando problemas futuros? Não estou dizendo que tenho 100% de certeza, mas o que acho que estou dizendo é que seus testes devem, em um mundo sem dúvida mais ideal que o nosso, cobrir todas as bases.
mike roedor
Você pode simular sim, com a qual possui uma dependência (janela de encaixe) que, se falhar, significa que você deseja executar novamente mesmo que o código não tenha sido alterado. Eu gostaria de enfatizar que esse pensamento não é para testes de unidade ou testes onde 1. você tenta evitar dependências 2. ou pelo menos zomba deles usando a estrutura de teste, mas quando eles são realmente "fornecidos", se você quiser.
precisa saber é o seguinte
2
__ se nenhum código foi alterado, por que você precisa testar novamente? __ Você já ouviu falar sobre testes de integração?
Bogdan Mart