Dicas de teste sobrecarregadas para 2019: um tutorial de teste de automação Java

Publicados: 2022-03-11

Todos os anos, engenheiros de automação de teste de todo o mundo pesquisam as ferramentas e técnicas mais recentes para tornar sua estrutura de automação de teste mais estável, rápida e fácil de usar e manter. Isso é vital para garantir a adoção generalizada contínua de sua estrutura dentro de sua empresa. Em geral, frameworks inchados e desatualizados saem de moda rapidamente.

Neste artigo, veremos algumas das maneiras de atualizar sua estrutura para 2019 e como se preparar para 2020. Para melhorar minha estrutura, sempre me concentro nos “pontos problemáticos”. Essas são as áreas que são complexas de configurar ou causam mais falhas. Identifiquei três áreas principais que queria simplificar ou melhorar:

  1. Grade de selênio
  2. Espera
  3. Chrome DevTools

O Selenium Grid é notoriamente complicado de configurar e pode falhar sem aviso prévio. Eu queria ver o que, se alguma coisa, havia melhorado aqui. Eu também queria investigar se alguma nova waits havia sido adicionada à API do Selenium para melhorar a estabilidade de qualquer teste que eu criasse. Por fim, queria ver se poderia começar a interagir com o Chrome DevTools por meio do Selenium, que se tornou uma parte essencial do kit de ferramentas de qualquer testador.

Dica nº 1: Dockerize sua grade de Selenium

O Selenium Grid é notoriamente difícil de configurar, instável e difícil de implantar ou controlar a versão em um pipeline de CI. Uma maneira muito mais fácil, estável e de fácil manutenção é usar as imagens pré-criadas do Selenium Docker.

Nota: A única desvantagem deste método é que o IE (Internet Explorer) não é suportado, pois ainda não é possível contentorizar o sistema operacional Windows.

Configurando

Para começar a funcionar, primeiro você precisa ter o Docker e o Docker Compose instalados em sua máquina. Se você estiver executando o Windows 10 ou um Mac, ambos serão instalados por meio da área de trabalho do Docker.

Iniciando sua grade

O repositório oficial do Selenium no Docker Hub contém imagens do Docker pré-criadas para seu Selenium Hub e Firefox e Chrome Nodes.

A maneira mais fácil de usá-los em um Selenium Grid local é construir um arquivo Docker Compose dentro do diretório raiz do seu projeto. Nomeie o arquivo como docker-compose.yml para manter as coisas simples.

Incluí um exemplo abaixo que cria o seguinte Grid:

  • Um único hub de selênio
  • Um nó do Chrome
  • Um nó do Firefox
 #docker-compose.yml version: "3" services: selenium-hub: image: selenium/hub:3.141.59-neon container_name: selenium-hub ports: - "4444:4444" chrome: image: selenium/node-chrome:3.141.59-neon volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444 firefox: image: selenium/node-firefox:3.141.59-neon volumes: - /dev/shm:/dev/shm depends_on: - selenium-hub environment: - HUB_HOST=selenium-hub - HUB_PORT=4444

O arquivo Docker Compose descreve a configuração do seu Grid. Para obter mais informações sobre como criar arquivos do Docker Compose, consulte a documentação oficial.

Para iniciar seu Grid, basta usar qualquer janela de terminal (uma janela powershell ou cmd no Windows) para executar o seguinte comando no diretório raiz do seu projeto:

 docker-compose up

Conectando-se à rede

Você pode se conectar ao seu Selenium Grid exatamente da mesma maneira que faz normalmente, pois o Hub está escutando na porta 4444 da sua máquina local. Aqui está um exemplo em que configuramos nosso Driver para usar nosso Chrome Node.

 // Driver.java protected static RemoteWebDriver browser; DesiredCapabilities cap = new DesiredCapabilities(); ChromeOptions chromeOptions = new ChromeOptions(); cap.setCapability(ChromeOptions.CAPABILITY, chromeOptions); cap.setBrowserName("chrome"); driver = new RemoteWebDriver(cap);

Você pode usar a biblioteca TestNG para executar seus testes em vários nós em paralelo, como de costume.

Vale a pena notar que é possível ter vários navegadores em execução em cada nó. No entanto, isso é desencorajado e o uso de um navegador por nó é considerado a melhor prática para um desempenho ideal.

Dicas e truques adicionais

Se você quiser ver o que está acontecendo no navegador para poder depurar seus testes, vale a pena ter uma versão de debug do arquivo docker-compose.yml que baixa os nós do navegador de debug . Eles contêm um servidor VNC para que você possa observar o navegador enquanto o teste é executado.

Também é possível executar os navegadores sem cabeça para aumentar a velocidade (da maneira usual) e o Selenium também fornece versões base das imagens para que você possa criar suas próprias imagens se precisar de software adicional instalado.

Para criar uma versão estável do Grid para seu pipeline de CI, também é possível implantar seu Grid no Kubernetes ou Swarm. Isso garante que todos os Dockers sejam rapidamente restaurados ou substituídos em caso de falha.

Dica nº 2: esperas inteligentes

Como qualquer engenheiro de automação de teste sabe, as waits são cruciais para a estabilidade de sua estrutura de automação de teste. Eles também podem acelerar seu teste, tornando redundantes quaisquer sleeps ou pauses e superando problemas de rede lenta e entre navegadores. Veja abaixo algumas dicas para deixar suas waits ainda mais resilientes.

Tutorial de teste de automação Java nº 2: Operadores lógicos em esperas: seja específico com suas esperas

A classe ExpectedConditions cresceu ao longo do tempo e agora abrange quase todas as situações imagináveis. Embora ExpectedConditions.presenceOfElementLocated(locator) geralmente seja suficiente, é uma prática recomendada usar os métodos dentro da classe ExpectedCondition para cobrir todas as ações do usuário, incorporando-os em sua classe Actions.java . Isso protegerá seus testes contra a maioria dos problemas entre navegadores ou sites lentos.

Por exemplo , se clicar em um link resultar na abertura de uma nova guia, use ExpectedConditions.numberOfWindowsToBe(2) . Isso garantirá que a guia esteja lá antes de tentar alternar para ela.

Você também pode usar um wait para garantir a captura de todos os elementos presentes na página ao usar findElements . Isso pode ser especialmente útil se levar algum tempo para uma página de search retornar seus resultados. Por exemplo, esta linha:

 List<WebElement> results = driver.findElements(locators.RESULTS);

Pode resultar em uma matriz de List vazia se os resultados da pesquisa ainda não tiverem sido carregados. Em vez disso, é melhor usar a condição esperada numberOfElementsToBeMoreThan para esperar que os resultados sejam maiores que zero. Por exemplo:

 WebElement searchButton = driver.findElement(locators.SEARCH_BUTTON); searchButton.click(); new WebDriverWait(driver, 30) .until(ExpectedConditions .numberOfElementsToBeMoreThan(locators.RESULTS, 0)); List<WebElement> results = driver.findElements(locators.RESULTS); results.get(0).click();

Agora, seu comando findElements só será executado depois que os resultados da pesquisa forem retornados.

Essa wait também é útil para encontrar um único elemento quando você está lidando com um front-end que não funciona bem com o Selenium (por exemplo, sites Angular). Criar um método como esse protegerá seus testes, tornando-os muito mais estáveis.

 protected static WebElement waitForElement(By locator){ try { new WebDriverWait(browser, 30) .until(ExpectedConditions .numberOfElementsToBeMoreThan(locator, 0)); } catch (TimeoutException e){ e.printStackTrace(); Assert.fail("Timeout: The element couldn't be found in " + WAIT + " seconds!"); } catch (Exception e){ e.printStackTrace(); Assert.fail("Something went wrong!"); } return browser.findElement(locator); }

É até possível esperar que os elementos não sejam mais visíveis. Isso é especialmente útil se você estiver esperando que um pop-up desapareça depois de clicar no botão OK ou Save antes de prosseguir com o teste.

 WebElement okButton = driver.findElement(locators.OK_BUTTON); okButton.click(); new WebDriverWait(driver, 30) .until( ExpectedConditions .invisibilityOfElementLocated(locators.POPUP_TITLE) );

Todos os métodos descritos acima e mais estão listados na documentação oficial. Vale a pena gastar dez minutos lendo todas as possibilidades e melhorando a estabilidade do seu framework.

Tutorial de teste de automação Java nº 2: operadores lógicos em espera

Uma boa maneira de criar resiliência em suas waits é usando operadores lógicos. Por exemplo, se você quiser verificar se um elemento foi localizado E se é clicável, use o seguinte código (observe que esses exemplos retornam um valor booleano):

 wait.until(ExpectedConditions.and( ExpectedConditions.presenceOfElementLocated(locator), ExpectedConditions.elementToBeClickable(locator) ) );

O operador OR seria apropriado se você não tivesse certeza se o título da página poderia ou não mudar. Então você pode incluir uma verificação do URL se a primeira condição falhar, para confirmar que você está definitivamente na página certa.

 wait.until(ExpectedConditions.or( ExpectedConditions.titleIs(expectedTitle), ExpectedConditions.urlToBe(expectedUrl) ) );

Ou se você quiser garantir que uma caixa de seleção não esteja mais habilitada depois que uma ação for executada na página, o operador NOT é apropriado.

 wait.until(ExpectedConditions.not( ExpectedConditions.elementToBeClickable(locator) ) );

O uso de operadores pode tornar suas waits mais resilientes e resultar em testes menos frágeis.

Dica 3: Chrome DevTools: simulando condições de rede

A execução do seu aplicativo Web em localhost ou em uma rede local pode dar uma falsa impressão sobre seu desempenho ao ser executado em estado selvagem. A capacidade de limitar várias velocidades de upload e download fornecerá uma representação melhor de como seu aplicativo será executado na Internet, onde os tempos limite podem causar falhas nas ações. Podemos começar a simular isso usando o poder do DevTools do Chrome.

O código a seguir abrirá a página inicial da Toptal usando diferentes velocidades de download e upload. Primeiro, armazenaremos nossas velocidades em um provedor de dados TestNG usando o seguinte código:

 import org.testng.annotations.DataProvider; public class ExcelDataProvider { @DataProvider(name = "networkConditions") public static Object[][] networkConditions() throws Exception { return new Object[][] { // Upload Speed, Dowload Speed in kb/s and latency in ms. { 5000 , 5000, 5 }, { 10000, 7000, 5 }, { 15000, 9000, 5 }, { 20000, 10000, 5 }, { 0, 0 }, }; } }

Observação: a limitação de upload e download está em kb/s e a latência está em ms .

Em seguida, podemos usar esses dados para executar nosso teste em diferentes condições de rede. Dentro do teste, o CommandExecutor executará o comando na sessão atual do navegador. Isso, por sua vez, ativará as configurações necessárias na funcionalidade Ferramentas do desenvolvedor do Chrome para simular nossa rede lenta. O código dentro da instrução if pode ser incluído em um método @BeforeClass ao executar um conjunto de testes.

 import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.openqa.selenium.remote.Command; import org.openqa.selenium.remote.CommandExecutor; import org.openqa.selenium.remote.Response; public class TestClass { // load our data provider @Test(dataProvider = "networkConditions") public void test(int download, int upload, int latency) throws IOException { // only run if the network is throttled if (download > 0 && upload > 0) { CommandExecutor executor = driver.getCommandExecutor(); // create a hashmap of the required network conditions Map map = new HashMap(); // you can even test 'offline' behaviour map.put("offline", false); map.put("latency", latency); map.put("download_throughput", downloadThroughput); map.put("upload_throughput", uploadThroughput); // execute our code Response response = executor.execute( new Command(driver.getSessionId(), "setNetworkConditions", ImmutableMap.of("network_conditions", ImmutableMap.copyOf(map)))); } // Open the website driver.get("https://www.toptal.com/"); // You can then check that elements are loaded etc. // Don't forget to use waits! } }
Relacionado: Construa com confiança: um guia para testes JUnit

Dica de bônus: como gerenciar seus cookies

Os cookies do navegador podem causar diferentes comportamentos em seu aplicativo, dependendo de terem sido salvos ou não de uma sessão anterior (por exemplo, o aplicativo pode carregar com um usuário já conectado). É uma boa prática limpar seus cookies antes de cada execução de teste para garantir que eles não causem problemas.

O código abaixo permite que você exclua todos os seus cookies:

 driver.manage().deleteAllCookies();

Você também pode excluir um cookie pelo nome:

 driver.manage().deleteCookieNamed("CookieName");

Ou obtenha o conteúdo de um cookie:

 String myCookie = driver.manage().getCookieNamed("CookieName").getValue();

Ou obtenha todos os cookies:

 List<Cookie> cookies = driver.manage().getCookies();

Automação de testes em 2020: olhando para o futuro

O Selenium 4 será lançado nos próximos meses. Ainda está em desenvolvimento, mas como uma versão alfa já foi lançada, vale a pena dar uma olhada nas melhorias que ela oferecerá.

Nota: Você pode acompanhar o progresso deles observando o roteiro.

Padronização do W3C WebDriver

O Selenium não precisará mais se comunicar com o navegador por meio do protocolo JSON wire; em vez disso, os testes automatizados se comunicarão diretamente com o navegador. Isso deve abordar a famosa natureza esquisita dos testes do Selenium, incluindo a proteção contra atualizações do navegador. Espero que a velocidade de teste também aumente.

Uma grade de selênio mais simples

O Selenium Grid será mais estável e fácil de configurar e gerenciar no Selenium 4. Os usuários não precisarão mais configurar e iniciar hubs e nós separadamente, pois o grid atuará como um nó e hub combinados. Além disso, haverá melhor suporte para o Docker, testes paralelos serão incluídos nativamente e fornecerão uma interface do usuário mais informativa. O rastreamento de solicitação com Hooks também o ajudará a depurar sua grade.

Documentação

A documentação do Selenium receberá uma revisão muito necessária, não tendo sido atualizada desde o lançamento do Selenium 2.0.

Alterações na API

O suporte para os navegadores Opera e PhantomJS será removido. A execução sem cabeça pode ser executada com o Chrome ou Firefox, e o Opera é construído no Chromium e, portanto, o teste do Chromium é considerado suficiente para este navegador.

WebElement.getSize() e WebElement.getLocation() agora foram substituídos por um único método WebElement.getRect() . No entanto, como eles costumam ser usados ​​para criar capturas de tela de um único elemento, vale a pena saber que também haverá um comando de API para capturar uma captura de tela de um elemento no Selenium 4.

Para WebDriver Window , os métodos getPosition e getSize serão substituídos pelo método getRect e os métodos setPosition e setSize serão substituídos pelo método setRect . os métodos fullscreen e minimize estarão disponíveis, para que essas ações possam ser executadas em seu teste.

Outras mudanças notáveis:

  • A classe Options para cada navegador agora estenderá a classe Capabilities .
  • Um driver.switchTo().parentFrame() foi adicionado para facilitar a navegação de quadros.
  • serão incluídos nice localizadores que operam em um nível superior aos atuais. Eles serão uma subclasse de By .
  • Haverá uma implementação da API DevTools , permitindo que os usuários aproveitem os recursos oferecidos usando o Chrome Debugging Protocol (e equivalentes em outros navegadores). Esses incluem:
    • Capturas de tela de página inteira (incluindo elementos fora da tela).
    • Registros de streaming.
    • Aguardando eventos de mutação na página.
  • Muitos métodos e classes obsoletos também serão excluídos.

Nota: Você pode obter uma versão Alpha do Selenium 4 no repositório Maven. É altamente recomendável testar isso em sua estrutura atual (de preferência em uma ramificação de sandbox), para que você esteja pronto para a mudança.

Conclusão

Neste artigo, abordei algumas áreas em que melhorei minha estrutura de automação de teste para melhor. Agora está mais estável e utilizável do que antes, o que terá um impacto positivo em todos os envolvidos no ciclo de vida de entrega de software.

Fazer as alterações que descrevi acima é um bom começo, no entanto, eu recomendo que você revise toda a sua estrutura para "pontos problemáticos", pois pode haver melhorias que você pode fazer que não abordei. Por exemplo, você está usando o WebDriver Manager para gerenciar seus drivers ou ainda está atualizando-os manualmente?

Eu também recomendaria definir uma data para fazer isso pelo menos uma vez por ano, embora o ideal seja a cada seis meses. No artigo, incluí as mudanças que estão chegando no Selenium 4.0. Por favor, revise as versões alpha do Selenium por si mesmo. As mudanças serão dramáticas e você precisará estar preparado. Espero que você tenha achado isso útil. Se você descobrir quaisquer novos métodos ou técnicas enquanto faz uma limpeza de primavera em sua estrutura, compartilhe-os com outros leitores deste blog adicionando-os à seção de comentários abaixo.

Além disso, se você quiser dar uma olhada nos testes automatizados no Selenium, e como você pode usar os modelos Page Object para escrever rotinas de teste que podem ser mantidas e reutilizáveis, confira Automation in Selenium: Page Object Model and Page Factory .

Relacionado: A linguagem Dart: quando Java e C# não são suficientemente nítidos