Na aula passada conseguimos o básico de um teste funcional automatizado com uso do Selenium e Cucumber. No entanto, ainda há o que melhorar, e novas peças a serem adicionadas nesse “LEGO” da automação. Aliás, essa é uma boa analogia quando trabalhamos com Selenium: nós podemos montar os testes utilizando os componentes (peças) que desejamos. Por exemplo, até o momento juntamos as “peças” Eclipse, Selenium, Cucumber, Maven, ChromeDriver, e agora o ExtentReports.
Vamos iniciar a aula de hoje ajustando um pequeno detalhe em nossa classe feature:
Vamos ajustar a descrição do campo “Feature” acima para a descrição mostrada abaixo:
Muito mais claro agora: nossa feature vai cuidar do cadastro de clientes.
Vamos à parte do ExtentReports. Para isso, acesse o endereço http://extentreports.com/
Clique sobre o botão “Community Edition”, pois vamos utilizar a versão gratuita.
Ao clicar, teremos as informações necessárias para utilizar o Maven (sim, mais uma “peça LEGO” que será adicionada através do Maven):
<!– pom.xml –>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.0.3</version>
</dependency>
Com essas informações, vamos abrir o pom.xml do nosso projeto no Eclipse, acessar a aba “Dependencies” e então clicar em “Add…”
Na janela que abrir, inserimos as informações conforme ilustrado abaixo:
Após clicar em OK, a dependência será adicionada:
Após salvar o projeto no Eclipse, é hora de utilizarmos essa biblioteca de reports. Ao contrário do TestComplete, onde já vem tudo configurado (só arrastar e usar), aqui é preciso ter um pouco de “paciência”.
Na classe “TestRule.java”, crie uma variável estática privada chamada “private static ExtentHtmlReporter htmlReporter; ”. Após criá-la, é preciso realizar o import correto. A imagem abaixo ilustra a criação da variável bem como a realização do import que deve ser feito:
Em seguida, crie uma nova variável privada estática: “private static ExtentReports extentReport;”. A imagem abaixo ilustra tanto a variável quanto o import a ser utilizado:
Finalmente, adicionamos uma terceira variável privada estática: “private static ExtentTest feature; ”. A criação da variável bem como o import é mostrado abaixo:
Mas, o que são essas três variáveis? Abaixo uma breve explicação de cada tipo de variável:
- ExtentHtmlReporter: indica o TIPO de report que iremos gerar ao final do teste. Nesse caso, iremos criar um report do tipo html;
- ExtentReports: é como se fosse o “gerenciador” dos reports gerados;
- ExtentTest: é o teste propriamente dito. É nele que estarão os logs do cenário executado, informações, prints, etc…
Prosseguindo com o uso do extentReports, vamos modificar um pouco o método “beforeCenario” da classe “TestRule.java”, conforme ilustrado abaixo:
O código destacado acima ilustra o que deve ser adicionado dentro do método “beforeCenario”.
Abaixo uma descrição do esse código faz:
Linha 27: inicializa a variável “extentReport”;
Linha 28: inicializa a variável “htmlReport” e diz ONDE SERÁ CRIADO O HTML (“src/test/resources/htmlReporter.html”). Nesse caso, será criado em um diretório dentro do projeto.
Linha 29: adiciona o “htmlReporter” ao “extentReport” (lembre-se que o “extentReport” é como um gerenciador encarregado de organizar os reports).
Linha 26: o if é para verificar se o extentReport já não foi inicializado previamente. Lembre-se que o método “beforeCenario” é sempre chamado antes do início de um novo cenário. Se o extentReport for inicializado todas as vezes que iniciar um cenário, a informação guardada por ele do cenário executado anteriormente será perdida. Então basta ele ser inicializado uma vez somente (no caso, na execução do primeiro cenário somente).
Linha 32: inicia um novo teste, recebendo como parâmetro o id do cenário que está sendo executado.
Agora, preste atenção no construtor do método “beforeCenario”. Foi adicionado a ele um parâmetro do tipo “Scenario”. É a partir dele que iremos pegar o id do cenário que está sendo executado. Abaixo é mostrado o import a ser realizado para utilizá-lo:
Esses eram os ajustes a serem feitos no método “beforeCenario” para utilização da biblioteca “ExtentReports”.
Finalizado os ajustes no método “beforeCenario”, é hora de criar o método “afterCenario”: esse método é chamado ao final de cada teste executado. A necessidade dele é simples: ao final do cenário precisamos chamar o método “extentReport.flush()”, que é o responsável por gravar as informações coletadas do cenário no report html. Sem ele nenhuma informação do teste seria gravada no report. Abaixo tem-se o método (sem os imports realizados):
Vamos analisar o código e o método:
Linha 47: o método comentado anteriormente, que realiza a gravação das informações coletadas no report;
Linha 46: Um exemplo de log a ser coletado. Para isso basta chamar o método “extentTest.log” passando dois parâmetros: o primeiro indica o tipo de log que será coletado (PASS, ERROR, FAIL, INFO, …, semelhante ao TestComplete). O segundo parâmetro é um texto que irá aparecer no log. Nesse exemplo, estamos dizendo que o cenário foi executado com sucesso.
Abaixo as imagens mostrando os imports a serem realizados:
Após os imports realizados:
Agora é hora de executar o teste automatizado:
Abaixo o resultado da execução:
E quanto ao report gerado? Ele é mostrado abaixo:
Esse foi o report gerado. Obviamente ele está bem simples pois só tem uma entrada de log: o log que diz que o cenário foi executado com sucesso.
E quanto aos prints? Precisamos de prints, precisamos de evidências. Na próxima aula!!!
EXERCÍCIO: o objeto desse exercício é fixar o conhecimento aprendido na aula relacionado à biblioteca ExtentReports. Para isso:
- Releia com atenção a aula de hoje;
- Acesse a página http://extentreports.com/ conforme mostrado na aula para obter o xml da versão Community mais atual do ExtentReports necessário para utilização do Maven;
- Com as informações obtidas desse xml, abra o pom.xml do nosso projeto no Eclipse e adicione essas informações para que o projeto possa utilizar o ExtentReports conforme visto na aula;
- Na classe “TestRule.java”, crie as variáveis estáticas privadas “htmlReporter”, “extentReport” e “extentTest” conforme apresentado na aula, não esquecendo de realizar os imports devidos;
- Atualize o método “beforeCenario” da classe “TestRule.java” conforme demonstrado na aula para fazer uso do ExtentReport;
- Na classe “TestRule.java” crie o método “afterCenario” conforme visto na aula, não esquecendo de realizar os imports necessários;
- Revise seu projeto e execute o teste. Após executá-lo com sucesso, analise o report html gerado: abra-o, observe-o, conheça-o!;
Fiquei com uma dúvida,
Nesse método de affetercenários, mesmo com os passos do extendsreport eu posso colocar um driver.close();
CurtirCurtir
Boa noite! Não só pode como deve 🙂
Inclusive eu comento lá na aula 6 mais detalhes sobre o driver.close() e a importância de utilizá-lo;
CurtirCurtir
Olá, tudo bem?
Poderia meu auxiliar? Eu fiz esses steps, porém estou recebendo a seguinte mensagem na Console: No reporters were started. Atleast 1 reporter must be started to create tests.
Poderia me ajudar? obrigada
CurtirCurtir
Boa noite!
Posso sim!
Bom, eu tentei reproduzir essa mensagem de erro e consegui fazer isso comentando a linha 29 (extentReport.attachReporter(htmlReporter);), então eu acredito que o teu problema esteja no método beforeCenario. Provavelmente é algum detalhe que passou despercebido ali.
Tenta revisar ele para ver se não há alguma linha faltando, ou algum caminho errado.
Me avise se conseguiu resolver o problema!
Se não conseguiu, poste aqui o teu método para olharmos.
CurtirCurtir
Olá, Cristiano, realmente não estou conseguindo kkkk =(
Criei um post no Stack overflow: https://stackoverflow.com/questions/53280486/html-file-is-not-getting-created-extent-report-junit
Tentei umas variações com o @Before. O que vc acha? Obrigada!
CurtirCurtir
Boa noite!
Bom, tem como tu colar aqui os imports que tem na tua classe?
Aquelas variações ali são com o BeforeMethod e AfterMethod do Junit?
Aquele @Test também foi uma tentativa?
Uma dúvida: o que é aquele freemaker que tu comenta lá no stack overflow? Tu instalou ele ou ele apareceu ali automaticamente?
CurtirCurtir
Ah! Esqueci de perguntar também: o que é a tua classe Execute? Vi que tu classe Steps extende a Execute, e ao mesmo tempo dentro de um dos steps tu cria uma instância da Execute (Execute Executar = new Execute();)
CurtirCurtir
Olá, Cristiano =)
Meus imports:
import org.junit.Test;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeTest;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
import CompraVtex.CompraVtex.Execute;
import CompraVtex.CompraVtex.TestData;
import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
Os imports com o testng foi uma tentiva de cria-lo com o TestNG kkkkkkkkk
Então, quando eu tento executar com o @Before ele esta dando essa mensagem de erro:
“Failure in before hook:Steps.beforeCenario(Scenario) Message: java.lang.NoClassDefFoundError: freemarker/template/TemplateModelException”
Procurando na internet vi que alguns casos o pessoal resolveu colocando aquela dependencia no projeto, eu coloquei, mas continua o mesmo erro.
Na minha classe Execute estão os WebElements, um exemplo:
public void Login() throws Exception {
Thread.sleep(5000);
WebElement TipoLogin = driver.findElement(By.id(“vtexIdUI-google-plus”));
TipoLogin.click();
}
e na Steps:
@Test
@And(“cliquei no botao de Login com google”)
public void Login() throws Exception {
Execute Executar = new Execute();
getscreenshot(“01 Login”,”01 – Acessando URL”);
Executar.Login();
}
muito obrigada, pela atenção e ajuda, Cristiano!
CurtirCurtir
Oi!
Olhando teus imports, vejo que tem um misto de imports do junit, testng, cucumber e que tua mensagem de erro agora está relacionada ao freemaker.
Como eu nunca tive esses erros que tu apresentou, desconfio que possa ser algum conflito entre as bibliotecas/imports.
Percebi que no teu projeto tu está estruturando ele de uma maneira própria, adaptando ele pras tuas necessidades, correto?
Uma sugestão que eu tenho seria começar um projeto de testes do zero, bem simples, usando a estrutura mostrada aqui no blog. Faça-o incremental, adicionando parte por parte e testando, pra tentar isolar o problema.
Por exemplo, faça um cenário de testes SEM o extentReports, utilizando o Cucumber somente (atenção para os imports corretos) e só depois de certificar-se de que ele está rodando perfeitamente, adicione o extentReports como mostrado aqui.
Me mantenha informado do teu progresso. 🙂
Ah! Fugindo um pouco do assunto, uma dica para o teu thread.sleep quando tu resolver o problema do extentreports: dê uma pesquisada por WebdriverWait para utilizá-lo no lugar do thread.sleep 😉
CurtirCurtir
Cristiano boa noite,
Ao tentar utilizar desta forma o meu apresento NullPointer na classe steps. Abri um stack. Vc poderia me ajudar? https://pt.stackoverflow.com/questions/372248/nullpointer-ao-solicitar-execu%C3%A7%C3%A3o-extentreport
CurtirCurtir
Boa noite!
Olhando lá no stack, vi que teu método está como
@BeforeClass
public static void beforeCenario(Scenario cenario){
Pergunta:
1 – está utilizando o @Before do Cucumber? Pergunto pois tu está utilizando o @BeforeClass, e se tu for olhar numa das imagens da aula 3 (aula anterior a essa), verá que utilizo o @Before, onde enfatizo a utilização do import do cucumber relativado a ele.
Teria como colar aqui os imports da tua classe para verificarmos?
CurtirCurtir
Olá prezados,
Tudo bem?
Como faço para exibir no relatório “Extent Report” algum trecho do log do Junit no caso de Falha?
Exemplo: Falha em um Assert e etc
CurtirCurtir
Boa noite!
Desculpe a demora em responder, eu havia retirado um dente do siso ontem, então eu estava de repouso (ainda estou, na verdade).
Bom, essa é uma pergunta bem interessante. E eu até fui fazer umas pesquisas sobre isso pois eu não sabia se era possível. Eis que encontrei a resposta num post do stackoverflow 🙂
Nesse post eu encontrei a base do método que ensina como fazer: https://stackoverflow.com/questions/42542557/how-to-get-the-exception-that-was-thrown-when-a-cucumber-test-failed-in-java
Eu então o adaptei à nossa realidade aqui no blog, e criei o método abaixo dentro da classe TestRule baseado no exemplo do stackoverflow:
private void logError(Scenario cenario) {
Field field = FieldUtils.getField(((ScenarioImpl) cenario).getClass(), “stepResults”, true);
field.setAccessible(true);
try {
ArrayList results = (ArrayList) field.get(cenario);
for (Result result : results) {
if (result.getError() != null)
extentTest.log(Status.FAIL,
“Cenario ” + cenario.getName() + ” executado com falhas! : ” + result.getError());
}
} catch (Exception e) {
extentTest.log(Status.FAIL, “Error while logging error: ” + e.getMessage());
}
}
Depois disso, eu chamei esse método dentro do método afterScenario passando por parâmetro o cenário, como mostra o trecho de código abaixo:
if (cenario.isFailed()) {
extentTest.log(Status.FAIL, “Cenário ” + cenario.getName() + ” executado com falhas!”);
logError(cenario);
extentReport.flush();
}
Importante lembrar que quando eu criei o método novo na classe TestRule, vários imports precisaram ser feitos. Vou deixar abaixo a lista dos novos imports que adicionei aqui na minha classe TestRule. Com eles o método funcionou aqui. Caso o método falhe pra ti, talvez algum import esteja diferente:
import java.lang.reflect.Field;
import java.util.ArrayList;
import org.apache.commons.lang3.reflect.FieldUtils;
import cucumber.runtime.ScenarioImpl;
import gherkin.formatter.model.Result;
Aqui um exemplo de um erro que eu simulei em um caso de teste e que foi coletado no log:
Cen�rio Inserir Cliente Pessoa Fisica executado com falhas! : java.lang.AssertionError: N�o exibiu a mensagem de Sucesso
Veja que é a mensagem do assert onde ocorreu a falha:
Assert.assertTrue(“Não exibiu a mensagem de Sucesso”, blnExibiuMensagemSucesso);
Era isso que tu estava procurando fazer? Qualquer dúvida, só perguntar!
CurtirCurtir
Bom dia,
Obrigado pelo retorno.
Mas esqueci de um “pequeno detalhe”, nos meus projetos não utilizo Cucumber..rsrs..
Mas irei dar uma pesquisada.
😀
CurtirCurtir
Na método abaixo, estou com alguns problemas:
1 – results (Dentro do for – “Type mismatch: cannot convert from element type Object to Result”);
2 – Status (Tem que importar alguma dependência?);
Se preferir posso enviar um print da classe.
private void logError(Scenario cenario) {
Field field = FieldUtils.getField(((ScenarioImpl) cenario).getClass(), “stepResults”, true);
field.setAccessible(true);
try {
ArrayList results = (ArrayList) field.get(cenario);
for (Result result : results) {
if (result.getError() != null)
extent.log(Status.FAIL,
“Cenario ” + cenario.getName() + ” executado com falhas! : ” + result.getError());
}
} catch (Exception e) {
extent.log(Status.FAIL, “Error while logging error: ” + e.getMessage());
}
}
Você poderia me ajudar?
CurtirCurtir
Consegui. rsrsrs
Muito obrigado.
CurtirCurtir
Boa noite!
Desculpe a demora, hehehe!
Que bom que conseguiu 🙂
CurtirCurtir
Boa tarde Cristiano
Tenho 3 cenários, porem 2 deles uso esquema de cenário, poderia me auxiliar como tratar o report, ele até gera o relatório, mas como se eu tivesse somente um cenário e agrupa os demais nele.
CurtirCurtir
Boa noite!
Tudo bem?
Bom, não sei se eu entendi bem a tua dúvida. Me corrija se eu não entendi corretamente.
Acredito que tua dúvida é que o relatório está colocando o resultado de dois cenários como um só, e teu cenário é similar ao exemplo abaixo?
@regressivo1
Scenario Outline: Inserir Cliente Pessoa Fisica
Given efetuei login no sistema utilizando o usuario paul e a senha paul
And acessei o menu Clientes >> Inserir
When na tela Dados de Identificacao informo os dados de Pessoa Fisica: ,,, e
And na tela Dados de Identificacao clico em Avancar
And na tela Enderecos informo os enderecos
And na tela Enderecos clico em Salvar
Then na tela Enderecos sera exibida mensagem de sucesso
Examples:
| nome | email | data_nascimento | sexo | estado_civil |
| Automação Fora da Caixa | automacao@foradacaixa.com.br | 02/07/1990 | Masculino | Solteiro |
| Automação Fora da Caixa 2 | automacao2@foradacaixa.com.br | 03/09/1993 | Feminino | Solteiro |
Eu aqui executei o exemplo acima, e no report eu tive dois resultados distintos (2 cenários distintos), e com imagens distintas. Enfim, o teu problema está sendo imagens repetidas nos diferentes cenários? Ou o relatório mostrou só um cenário, com as duas execuções dentro dele?
Pergunta: como está teu método afterCenario? Ele está fazendo algo como “extentReport.flush();”? A cada linha da tabela acima o método afterCenario acaba sendo chamado.
Se eu não respondi a tua pergunta, me passe mais detalhes, certo? 😉
CurtirCurtir
Aula 4 – Coleta de Logs -biblioteca ExtentReports.
Dúvidas:
1- Só consigo gerar o relatório acessando o diretório.Não deveria gerar direto na ferramenta?
2- Na ferramenta eclipse o htmlReport não deveria aparecer na pasta :\src\test\resources?Não está aparecendo.
CurtirCurtir
Estranho! Teoricamente poderia ser possível visualizar o arquivo .html lá. Eu aqui pelo menos consigo visualizar ele, só que não é muito prático visualizar esse relatório por dentro do Eclipse. Eu acabo preferindo acessar o relatório no diretório e abrir direto com o browser.
CurtirCurtir
Olá Cristiano, estou com um problema.
precisamente nas seguintes linhas:
extentTest = extentReport.createTest(cenario.getId());
e
extentTest.log(Status.PASS, “Cenário ” + cenario.getName()+ ” executado com sucesso!”);
os seguintes campos estão com erro: getId e getName
O eclipse me informa os seguintes erros:
– The method getId() is undefined for the type Scenario
– The method getName() is undefined for the type Scenario
CurtirCurtir
Boa noite! Desculpe a demora.
É estranho ele não reconhecer esses métodos do objeto Scenario.
Dúvida: qual o import que tu está utilizando para o objeto scenário?
Em outras palavras: tu está utilizando esse import abaixo na tua classe?
‘import cucumber.api.Scenario;’
CurtirCurtir
Oi Cristiano, esse import funcionou 🙂 kkkkkkk
o estranho é que quando o eclipse informou a opção de importar o Scenario, ele fez o import com a seguinte descrição: “import com.aventstack.extentreports.gherkin.model.Scenario;”
Aí achei que estava certo. Mas substitui pelo “import cucumber.api.Scenario;” e funcionou.
Obrigado.
CurtirCurtir
O meu está com o seguinte erro
java.lang.NullPointerException
at com.vimalselvam.cucumber.listener.ExtentCucumberFormatter.result(ExtentCucumberFormatter.java:252)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at cucumber.runtime.Utils$1.call(Utils.java:40)
at cucumber.runtime.Timeout.timeout(Timeout.java:16)
at cucumber.runtime.Utils.invoke(Utils.java:34)
at cucumber.runtime.RuntimeOptions$1.invoke(RuntimeOptions.java:294)
at com.sun.proxy.$Proxy13.result(Unknown Source)
at cucumber.runtime.junit.JUnitReporter.result(JUnitReporter.java:121)
at cucumber.runtime.Runtime.runStep(Runtime.java:310)
at cucumber.runtime.model.StepContainer.runStep(StepContainer.java:44)
at cucumber.runtime.model.StepContainer.runSteps(StepContainer.java:39)
at cucumber.runtime.model.CucumberScenario.runBackground(CucumberScenario.java:59)
at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:42)
at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:102)
at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70)
at cucumber.api.junit.Cucumber.runChild(Cucumber.java:95)
at cucumber.api.junit.Cucumber.runChild(Cucumber.java:38)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at cucumber.api.junit.Cucumber.run(Cucumber.java:100)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
CurtirCurtir
Boa noite! Tudo bem? Consegue me passar mais detalhes do problema? Só pelo trace de erro não consegui identificar.
O erro acontece em que momento exatamente? É ao passar por um step? Algum método, classe? Tentou ir debugando o código até ver mais ou menos onde estoura o erro?
CurtirCurtir
Boa tarde.
Gostaria de saber se é possivel obter o nome da Feature atravez de algum getFeature?
Tipo, assim como pegamos o nome do Scenario, conseguiriamos pegar o nome da Feature?
CurtirCurtir
Bom dia! Desculpe pela demora em responder!
Acredito que não, o jeito seria pegar através do scenario mesmo. No link abaixo tem uns exemplos de como pegar, tem até um método pra isso, que acredito que possa te ajudar:
https://stackoverflow.com/questions/41394806/how-to-get-current-cucumber-feature-file-name-at-runtime-using-java
exemplo de código obtido ali do link acima, mas tem muitos outros exemplos lá:
private String getFeatureFileNameFromScenarioId(Scenario scenario) {
String featureName = “Feature “;
String rawFeatureName = scenario.getId().split(“;”)[0].replace(“-“,” “);
featureName = featureName + rawFeatureName.substring(0, 1).toUpperCase() + rawFeatureName.substring(1);
return featureName;
}
CurtirCurtir