Gerência de Projetos Dev & TI

23 jun, 2015

Automatizando testes funcionais no iOS com Calabash

Publicidade

No último artigo, falei sobre como automatizar os testes desenvolvidos em Cucumber para Android utilizando o Calabash. Recomendo a leitura deste artigo, porque vou relacionar diversos conceitos no texto de hoje com os apresentados no último. Lembrando que comecei a série com esse artigo aqui, que tem alguns conceitos iniciais e como configurar sua máquina.

Hoje, vou mostrar como automatizar os testes escritos em Cucumber para iOS, também utilizando o Calabash. Vale destacar aqui que o Calabash-Android e o Calabash-iOS são duas gems diferentes e que alguns dos passos pré-definidos no Calabash-Android podem não existir no Calabash-iOS e vice-versa. Por isso, bastante atenção quando estiver portando os testes de um SO para o outro.

Antes de iniciar o desenvolvimento, você precisa ter o Xcode instalado em sua máquina. Se você tem uma conta de desenvolvedor, pode baixá-lo diretamente da App Store. Também será necessário instalar o cocoapods, nosso aplicativo de exemplo vai utilizá-lo.

Com o ambiente configurado, vamos iniciar o desenvolvimento dos nossos testes. Primeiro precisamos definir um aplicativo a ser testado. O Alexandre Garrefa, da nossa equipe de desenvolvimento para iOS, realizou a implementação do Consulta CEP (aplicativo utilizado nos testes de Android) e disponibilizou em seu bitbucket. Este aplicativo recebe como parâmetro um CEP e exibe na tela o resultado da consulta desse valor em uma API dos Correios.

Clone esse repositório, abra essa pasta no terminal e execute o comando pod install para baixar as dependências. Depois, é só abrir esse projeto no Xcode (open ConcreteTest.xcworkspace). Tente executá-lo uma vez em um simulador. Assim que ele estiver executando com sucesso, podemos iniciar o desenvolvimento dos nossos testes.

Para facilitar o desenvolvimento, assim como o Calabash-Android, o Calabash-iOS possui um gerador que cria a estrutura inicial do projeto. Para executá-lo, abra a pasta do projeto que acabou de clonar no terminal e execute o comando calabash-ios gen. Este comando irá gerar os seguintes arquivos:

Oscar1

A estrutura é bastante similar à gerada pelo Calabash-Android. Nela, podemos ver a pasta features, que contém uma feature inicial chamada my_first.feature, um arquivo chamadocalabash_steps.rb, que contém somente um comando para importar os passos já pré-definidos pelas bibliotecas do Calabash-iOS, e a pasta support, que contém os arquivos de configuração dos hooks e um com configurações de ambiente, que importa as bibliotecas necessárias para a execução dos testes.

Diferente do Android, para conseguirmos executar os testes com o Calabash-iOS, precisamos criar um novo target em nosso aplicativo. No primeiro artigo, expliquei um pouco da estrutura do Calabash iOS para entender o porquê da criação desse novo target. O Calabash iOS fornece um comando que realiza a adição desse target. Para isso, digite no terminal na pasta do projeto o seguinte comando:

calabash-ios setup

Durante a execução do comando, o Calabash irá perguntar qual Target você deseja clonar. Escreva o nome do Target desejado (normalmente o principal). O Calabash irá, então, clonar esse Target e incluir as referências para o servidor de testes. A clonagem é realizada para evitar que o servidor de testes seja enviado para produção. No caso do nosso projeto de teste, o Target clonado deve ser o ConcreteTest.

Volte agora para o projeto que está aberto no Xcode. Na tela “Project Navigator”, selecione o projeto e depois, à direita, selecione o target recém-criado (ConcreteTest-cal). Alguns pontos importantes a serem verificados são: se a assinatura do aplicativo está sendo realizada corretamente e se em Build Settings o campo Product Name apresenta o sufixo “-cal”. Em alguns casos, o Calabash não adiciona o sufixo e isso pode gerar problemas ao executar os testes, pois o nome do app com o servidor de testes será idêntico ao do app sem o servidor.

Uma coisa que percebi com a prática: é importante sempre executar, ao menos uma vez, o aplicativo com o servidor de testes do Calabash-iOS por meio do Xcode para garantir que ele está funcionando corretamente. Alguns erros podem acontecer durante a configuração, e você não encontrará nenhum log melhor do que o gerado pelo Xcode.

Com o aplicativo funcionando em um simulador, vamos criar os nossos cenários de teste. Como o nosso aplicativo de CEP possui as mesmas funcionalidades que o aplicativo do Android, aqui é interessante que sejam utilizadas as mesmas features para testes. Por isso, vamos copiá-las do post do Android. Substitua o conteúdo do arquivo my_first.feature pelas linhas abaixo:

# language: pt
Funcionalidade: Consultar CEP
 
  Cenário: Posso consultar um CEP
    Dado que estou na tela inicial
    Quando digitar um CEP
    E clicar no botão consultar
    Então devo ver o nome da rua na tela

Assim como no Android, vamos executar o nosso cenário para que o cucumber sugira as implementações desses passos. Porém, antes preciso explicar sobre duas variáveis de ambiente do Calabash iOS. São elas:

  • DEVICE_TARGET: em qual aparelho ou simuladores iremos executar os testes. A partir do SDK 8.0, os simuladores também possuem UUID’s. Para visualizar os simuladores disponíveis em sua máquina e seus UUID’s, execute no terminal o comando xcrun simctl list;
  • DEVICE_ENDPOINT: IP e porta do servidor de testes em um device físico. Quando os testes são executados nos simuladores, essa variável torna-se desnecessária, mas quando executados em um device físico é necessário indicar qual o IP do aparelho e a porta do Calabash, que por padrão é a 37265. Lembre-se que o computador deve ter acesso ao celular por meio da rede para que seu computador possa se comunicar com o servidor de testes no celular.

Finalmente, vamos executar os nossos testes. Vale destacar que o Calabash-iOS não possui a funcionalidade de instalar o aplicativo no simulador ou device, sendo esse outro motivo para executar sempre uma primeira vez pelo Xcode. Para executar o teste, verifique qual o simulador em que o Xcode instalou o aplicativo, pegue o UUID desse simulador como falado acima e execute o comando abaixo:

DEVICE_TARGET=UUID_do_simulador cucumber

Perceba que o simulador é aberto automaticamente. Isso é necessário para que o Calabash tenha controle sobre o processo do Instruments e possa executar ações (como touch e swipe) no aplicativo.

Finalizada a execução dos testes, você deverá ver uma saída parecida com a abaixo:

# language: pt
Funcionalidade: Consultar CEP
 
  Cenário: Posso consultar um CEP        # features/my_first.feature:4
    Dado que estou na tela inicial       # features/my_first.feature:5
    Quando digitar um CEP                # features/my_first.feature:6
    E clicar no botão consultar          # features/my_first.feature:7
    Então devo ver o nome da rua na tela # features/my_first.feature:8
 
1 scenario (1 undefined)
4 steps (4 undefined)
0m15.056s
 
You can implement step definitions for undefined steps with these snippets:
 
Dado(/^que estou na tela inicial$/) do
  pending # express the regexp above with the code you wish you had
end
 
Quando(/^digitar um CEP$/) do
  pending # express the regexp above with the code you wish you had
end
 
Quando(/^clicar no botão consultar$/) do
  pending # express the regexp above with the code you wish you had
end
 
Então(/^devo ver o nome da rua na tela$/) do
  pending # express the regexp above with the code you wish you had
end

Ao analisar esse resultado, podemos ver que as últimas linhas são sugestões do Cucumber sobre como os nossos passos poderiam ser implementados. Vamos aceitar essas sugestões e utilizá-las para substituir o conteúdo do arquivo step_definitions/my_first_step.rb.

Execute novamente os testes e veja que agora temos outro tipo de resposta, no qual não existe mais nenhuma sugestão de passos a implementar, mas uma exceção de pendência de implementação (Pending). Vamos então desenvolver os nossos passos.

Uma diferença entre o iOS e o Android é que no iOS não é necessário identificar com um ID cada um dos elementos criados na tela. Por isso, para que possamos identificar os elementos de forma que o Calabash-iOS possa reconhecê-los, precisamos inserir tags de acessibilidade nos campos que sofrerão interação com os testes. Para isso, volte para o projeto aberto no Xcode e na aba “Project Navigator” selecione o arquivo iPhoneStoryboard.storyboard.

Primeiro, vamos adicionar uma tag de acessibilidade para esse storyboard, de forma que possamos identificar essa tela quando estivermos executando os testes por meio do Calabash-iOS. Para isso, no painel “Document Outline”, selecione o elemento View, logo abaixo do elemento Main View Controller. Então, clique na terceira aba do painel “Utilities” e digite valor para a tag de acessibilidade, por exemplo: CEP_SCREEN.

Para finalizar, vamos incluir também uma tag de acessibilidade para o campo texto que recebe o número do CEP. Para isso, clique nesse campo e na terceira aba do “Utilities” e digite um valor para a tag de acessibilidade, por exemplo:  CAMPO_TEXTO_CEP.

Salve as alterações realizadas e execute novamente o teste no simulador utilizando o botão com ícone de “Play”, para que essa nova versão do aplicativo seja instalada no simulador. Lembre-se sempre de fazer isso, pois o Calabash não possui a funcionalidade de instalar os aplicativos iOS nos simuladores ou devices, você precisa fazer isso manualmente ou por meio do Xcode.

Voltemos à implementação do nosso primeiro passo. Nele, precisamos garantir que estamos na tela do CEP. Para isso, utilize o seguinte comando:

Dado(/^que estou na tela inicial$/) do
  wait_for(timeout: 5) { element_exists "* marked:'CEP_SCREEN'" }
end

Assim como no teste do Android, aqui estamos utilizando o comando wait_for. Esse comando espera por um determinado tempo (de segundos), até que uma query de busca seja executada com sucesso no aplicativo em execução. Caso isso não ocorra, esse comando lança uma exceção.

Analisando a linha implementada, é preciso saber que, se em 5 segundos não for encontrado um elemento no qual algum dos seus atributos possua o valor CEP_SCREEN, uma exceção será lançada. Atente-se para fato de estarmos utilizando marked e não id. Pois como comentei, agora estamos utilizando as tags de acessibilidade e não mais os ID’s dos elementos.

Execute novamente seus testes e veja o primeiro passo (“step”) passar. Então, vamos implementar o próximo. Para isso, utilize o código abaixo:

Quando(/^digitar um CEP$/) do
  touch("* marked:'CAMPO_TEXTO_CEP'")
  sleep(1)
  keyboard_enter_text "04565001"
end

Aqui podemos ver uma pequena diferença entre o Android e o iOS. Para evitar problemas com os valores inseridos no campo, no iOS é importante que eles sejam sempre feitos por meio do teclado. Por isso, para inserir um texto em um campo, precisamos tocar no campo para que o teclado seja exibido; esperar um segundo para que o teclado apareça completamente na tela e inserir o texto por meio do teclado. O Calabash-iOS já possui uma função que faz a inserção do texto (keyboard_enter_text), portanto, somente precisamos chamar essa função e passar o nosso CEP desejado como parâmetro. Nesse exemplo, estou usando o CEP da Concrete Solutions, em São Paulo.

Execute o teste novamente e veja os dois primeiros passos acontecerem. Caso você tenha erros de que teclado não está visível, pode ser que o seu simulador esteja configurado para não exibir o teclado. Se ao olhar o simulador você visualizar somente os botões Cancelar e Buscar na base da tela, é exatamente isso que está acontecendo. A exibição ou não do teclado é algo que ficou meio instável no SDK 8.1. Para resolver esse problema, pelo menos para a execução do próximo teste, clique no menu Hardware > Keyboard > Toogle Software Keyboard ou somente pressione Command (⌘) + K.

Depois dos dois primeiros passos, vamos implementar o nosso terceiro passo, que é responsável por clicar no botão de buscar. Para isso, utilize o código:

Quando(/^clicar no botão consultar$/) do
  touch("* marked:'Buscar'")
end

Pode-se ver que o comando touch irá clicar em qualquer elemento que contenha algum atributo com conteúdo igual a “Buscar”. Aqui poderíamos ter incluído uma tag de acessibilidade para esse botão também. Porém, como o aplicativo é simples e a ideia desse artigo é também ser simples, decidi simplificar a implementação desse passo, pois a tag de acessibilidade para esse botão teria que ser inserida por meio do código fonte e não mais por meio da interface visual do Xcode.

Execute o teste e veja os três passos passarem. Para fechar, podemos implementar o nosso último passo da seguinte forma:

Então(/^devo ver o nome da rua na tela$/) do
  wait_for(timeout: 5) { element_exists "* {text CONTAINS 'Rua Flórida'}" }
end

A implementação desse passo é idêntica à do Android: esperamos por 5 segundos até que exista um elemento na tela cujo texto contenha o conjunto de caracteres “Rua Flórida”.

Execute os testes e veja com orgulho todos os testes passarem. Com isso, terminamos de implementar nosso primeiro cenário. Como no Android, ainda podemos criar diversos cenários para esse aplicativo. Desafio: tente criar um teste que consulte três CEPs diferentes e ao clicar no botão Consultas Anteriores verifique se existe um elemento na tela que contenha em seu atributo texto o nome da rua do segundo CEP.

O Calabash-iOS também disponibiliza um console onde pode-se executar os comandos interativamente no simulador ou device. Para acessá-lo, execute o seguinte comando no terminal:

DEVICE_TARGET=UUID_do_simulador calabash-ios console

Aqui vale destacar uma diferença importante entre o Cabalash-Android e o Calabash-iOS. Como no iOS o servidor de testes é executado paralelamente ao aplicativo, é possível executar queries de consulta sem que o console tenha efetivamente aberto o aplicativo. Ou seja, se no simulador ou device o aplicativo com o servidor de testes do Calabash estiver aberto e você executar o comando query ‘*’, será retornado todos os elementos presentes na tela do aplicativo em um formato parecido com o do XML. Nesse caso, porém, não será possível realizar nenhum tipo de interação com o aplicativo (touch e swipe, entre outros). Portanto, sempre antes de iniciar a digitar os comandos no console, digite:

start_test_server_in_backgroudn

Assim fechamos uma explicação simples de como executar os testes de Calabash tanto no Android, como no iOS. Todos os arquivos gerados no exemplo de hoje, bem como os de Android, podem ser encontrados no meu Github.

Como um leitor atento, você percebeu que as features utilizadas são idênticas em ambos os SO’s, porém estão replicadas em lugares diferentes. Reuso não funciona com replicação, assim, apesar de falarmos que as features são iguais, elas precisam ser tratadas separadamente, pois estão replicadas.

No próximo artigo vou apresentar uma estrutura que acabará com essa replicação. Também falarei sobre uma terceira gem, chamada cs-bdd, que facilita o desenvolvimento de projetos de testes que funcionam tanto para Android, quanto para iOS. Essa gem disponibiliza um gerador único para criação do projeto de testes, diferente do que acontece hoje, quando tanto o Calabash-Android, quanto o Calabash-iOS possuem geradores independentes.

Dúvida, sugestões ou críticas? Só deixar no campo abaixo!