Executando Testes E2E com Gradle 9
Ao concluir esta lição, você será capaz de:
- Configurar diretórios de código-fonte e recursos dedicados para os testes End-to-End no Gradle 9.
- Compreender como declarar dependências exclusivas para a suíte de testes End-to-End (como Playwright ou Selenium).
- Orquestrar a ordem de execução das tasks (
test->integrationTest->endToEndTest) no ciclo de vida docheckebuild. - Executar os testes End-to-End isoladamente ou junto com toda a pirâmide de testes no Gradle 9.
Esta lição assume que:
1. Os Requisitos do Nosso Build no Gradle 9
Os requisitos do nosso script build.gradle.kts para os testes End-to-End são:
- Nossos testes End-to-End devem ter um diretório de código-fonte separado:
src/endToEndTest/kotlin(ousrc/end-to-end-test/kotlin). - Nossos testes End-to-End devem ter um diretório de recursos separado:
src/endToEndTest/resources(ousrc/end-to-end-test/resources). - Devemos ser capazes de executar isoladamente apenas os testes unitários (
./gradlew test), apenas os testes de integração (./gradlew integrationTest), apenas os testes End-to-End (./gradlew endToEndTest) ou todos os testes (./gradlew check). - Se um teste End-to-End falhar, nosso build também deve falhar.
- Testes unitários, testes de integração e testes End-to-End devem gerar relatórios HTML e XML em diretórios separados (
build/reports/tests/test,build/reports/tests/integrationTestebuild/reports/tests/endToEndTest).
Vamos começar configurando os diretórios de código e recursos dos nossos testes End-to-End.
2. Configurando os Diretórios de Código e Recursos dos Testes E2E
No curso original (escrito para Gradle 3), utilizava-se o plugin externo org.unbroken-dome.test-sets com a DSL testSets { endToEndTest { dirName = 'end-to-end-test' } }.
No Gradle 9.8+, utilizamos o plugin oficial nativo jvm-test-suite (testing { suites { ... } }), que cria automaticamente o source set endToEndTest, as configurações de dependência isoladas, a task endToEndTest e o diretório de relatórios próprio!
Adicionamos a suíte endToEndTest ao bloco testing do nosso arquivo build.gradle.kts da seguinte forma:
|
|
Por padrão, o jvm-test-suite configura automaticamente:
src/endToEndTest/kotlinpara o código-fonte em Kotlin dos testes E2E.src/endToEndTest/resourcespara os arquivos de recursos (como scripts SQL e properties) dos testes E2E.
Nota: Caso você queira manter o nome de diretório com hífens (
src/end-to-end-test/kotlinesrc/end-to-end-test/resources) exatamente como nos projetos legados, basta configurar osourceSetsexplicitamente:
1 2 3 4sourceSets.named("endToEndTest") { kotlin.setSrcDirs(listOf("src/end-to-end-test/kotlin")) resources.setSrcDirs(listOf("src/end-to-end-test/resources")) }
Vamos avançar e ver como declarar as dependências exclusivas dos nossos testes End-to-End.
3. Declarando as Dependências dos Nossos Testes End-to-End
Quando registramos a suíte endToEndTest, o Gradle cria duas configurações de dependência principais para ela:
endToEndTestImplementation(sucessora moderna da antigaendToEndTestCompile): Contém as dependências necessárias para compilar e rodar nossos testes End-to-End (comospring-boot-starter-test,playwright,selenium-javaeassertj-core).endToEndTestRuntimeOnly(sucessora moderna da antigaendToEndTestRuntime): Contém as dependências necessárias apenas em tempo de execução dos testes E2E (como drivers JDBC ou motores de log).
Podemos declarar essas dependências diretamente dentro do bloco dependencies da suíte endToEndTest (ou no bloco dependencies global do build.gradle.kts):
|
|
Compartilhando Utilitários de Teste com
java-test-fixtures:Se você quiser compartilhar classes de constantes (como
TaskseUsers) entretest,integrationTesteendToEndTestsem duplicar código, aplique o plugin`java-test-fixtures`nobuild.gradle.kts, coloque as classes compartilhadas emsrc/testFixtures/kotline adicioneimplementation(testFixtures(project()))nas suítes!
A seguir, configuraremos a task endToEndTest que executa nossos testes.
4. Configurando a Task que Executa os Testes End-to-End
Precisamos ajustar a configuração da task endToEndTest em dois passos para cumprir todos os requisitos do nosso build:
Primeiro, precisamos garantir a ordem lógica da pirâmide de testes quando invocamos ./gradlew check ou ./gradlew build:
- Os testes End-to-End devem ser executados como parte da task
check(e falhar o build caso algum teste E2E falhe). - Os testes de integração (
integrationTest) devem ser executados depois dos testes unitários (test) e antes dos testes End-to-End (endToEndTest). Isso garante que falhas rápidas em testes unitários ou de integração sejam reportadas antes de abrirmos um navegador real, e que os testes de integração sempre rodem mesmo se um teste E2E falhar.
Segundo, configuramos as opções do JUnit Platform e de logging na task endToEndTest:
- Configurar o JUnit Platform para incluir apenas os testes pertencentes à tag/categoria
endToEndTest(includeTags("endToEndTest")). - Configurar
testLogging { showStandardStreams = true }caso queiramos visualizar no console as mensagens gravadas emSystem.outouSystem.err(como logs de inicialização do navegador).
Veja como fica essa configuração completa no build.gradle.kts:
|
|
5. Iniciando e Parando a Aplicação Web
Antes de rodarmos os testes End-to-End, a aplicação web precisa estar em execução:
- Com Spring Boot 4.1 (Abordagem Padrão Moderna): Não precisamos de nenhum plugin adicional no Gradle! Quando anotamos nossas classes de teste E2E com
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)(ouDEFINED_PORT), o próprio Spring Boot Test inicia o servidor web embarcado antes dos testes da suíte e o desliga automaticamente ao final. - Com Spring Framework Clássico (WAR sem Spring Boot): No curso original para aplicações WAR legadas sem Spring Boot, utilizava-se o plugin Gretty (
org.akhikhl.gretty) configurado comintegrationTestTask = "endToEndTest", que executava as tasks:appBeforeIntegrationTest(subindo o Jetty na porta 8080) antes da task:endToEndTeste:appAfterIntegrationTestlogo depois.
6. Executando os Testes End-to-End no Terminal
Podemos executar nossos testes End-to-End utilizando uma destas duas opções:
Primeiro, para executar apenas os testes End-to-End (sem rodar os testes unitários ou de integração), executamos o comando:
|
|
Ao executar esse comando, o Gradle compilará o código principal e o source set endToEndTest, executará a task :endToEndTest e gerará o relatório HTML exclusivo em build/reports/tests/endToEndTest/index.html:
|
|
Segundo, se quisermos executar todas as camadas de teste (unitários, integração e End-to-End) na ordem exata da pirâmide (:test -> :integrationTest -> :endToEndTest), podemos usar um destes dois comandos:
|
|
Vamos resumir o que aprendemos nesta lição.
Resumo
Esta lição nos ensinou quatro pontos essenciais:
- Podemos adicionar source sets de teste customizados (
integrationTesteendToEndTest) ao nosso build Gradle 9 utilizando o plugin nativojvm-test-suite. - O plugin
jvm-test-suitecria configurações de dependência dedicadas (endToEndTestImplementationeendToEndTestRuntimeOnly) para isolar bibliotecas de automação de browser (como Playwright e Selenium) do código de produção e dos testes unitários. - Em aplicações Spring Boot 4.1, iniciamos e encerramos o servidor web diretamente via
@SpringBootTest(webEnvironment = ...), sem depender de plugins WAR externos como o Gretty. - Ordenamos a execução com
shouldRunAfterecheck { dependsOn(...) }para garantir que os testes rápidos (unitários e de integração) sempre rodem antes dos testes End-to-End.