Desenvolvimento

11 jun, 2015

Testes funcionais em dispositivos móveis: BDD e Cucumber

Publicidade

Este artigo inicia uma série de quatro textos técnicos nos quais falarei sobre testes funcionais em dispositivos móveis. Para começar, uma breve introdução aos conceitos de BDD e Cucumber, que serão necessários para entender os próximos textos. A intenção é apontar as principais funcionalidades e indicar onde procurar por mais informações. Ao final do post será apresentado o Calabash, que possibilita a execução dos testes escritos com o auxílio de Cucumber em dispositivos móveis iOS e Android.

Tanto em desenvolvimento web como mobile, a realização de diversos testes é essencial para garantir que o produto final não apresente erro ou mau funcionamento. Entretanto, no desenvolvimento mobile essa importância é aumentada, principalmente porque a frustração do usuário mobile pode gerar problemas muito maiores para a empresa. Por isso, destacamos sempre que a importância do QA para o desenvolvimento mobile é extremamente alta.

Existem diversos tipos de testes, mas vamos nos preocupar agora com os funcionais. É com eles que buscamos garantir que as funcionalidades do sistema em desenvolvimento (ou já desenvolvido) encontrem-se em conformidade com as especificações iniciais. Também existem diversas formas de realizar esse tipo de testes. Uma delas é o BDD, ou “Behavior Driven Development”.

O BDD foi concebido por Dan North, a partir de uma insatisfação com a falta de informações dos testes de TDD (“Test driven development”). Dan queria saber mais sobre o que deveria ser testado e como esse teste deveria ser realizado. A ideia principal do BDD é possibilitar que as funcionalidades do sistema sejam escritas em linguagem natural. Com isso, esse artefato pode ser utilizado como documentação, automatização de testes e auxílio aos desenvolvedores. Tanto os desenvolvedores quanto os analistas de testes, bem como o próprio cliente, podem escrever os casos de teste, visto que eles serão escritos em linguagem natural.

Existem diversas ferramentas que possibilitam o BDD, mas vamos nos concentrar em uma delas, o Cucumber. Com ele, as funcionalidades do sistema são escritas em arquivos de texto e em uma linguagem de domínio específico chamada Gherkin, muito semelhante à linguagem natural, mas que contém algumas palavras chaves. Vale destacar que Gherkin aceita mais de 40 línguas.

Os testes de BDD são compostos, basicamente, por arquivos que especificam as funcionalidades (“features”) e por arquivos de definição de passos (“steps”). Os arquivos com as funcionalidades são compostos por cenários, que exemplificam uma ou mais regras de negócio do sistema. Como exemplo, pense em um simples fluxo de login. Um provável arquivo de funcionalidades seria:

# language: pt
Funcionalidade Login
    Texto com a descrição da funcionalidade

Cenário: Como um usuário válido, posso logar no sistema
    Dado que estou na tela de Login
    Quando digitar credenciais válidas
    E clicar no botão de login
    Então devo acessar a Home do sistema

Cenário: Como um usuário inválido, devo visualizar uma mensagem de erro e continuar na página de Login
    Dado que estou na tela de Login
    Quando digitar credenciais inválidas
    E clicar no botão login
    Então devo ver uma mensagem de erro
    E devo estar na tela de Login

No exemplo acima, a primeira linha é um comentário que indica para o Cucumber que esse arquivo será escrito em português (pt). A segunda linha contém a palavra reservada “Funcionalidade” seguida de um identificador para essa funcionalidade. Todas as linhas entre a segunda e a que contém a palavra reservada “Cenário” determinam um comentário no qual pode-se descrever, da forma que desejar, as funcionalidades. Os cenários são as “unidades executáveis” dos testes e normalmente representam uma fração da funcionalidade e contém os passos necessários para que um usuário que utiliza a aplicação possa validar essa fração.

Para os cenários acima, caso eles sejam executados utilizando o Cucumber, um pedaço do retorno seria:

Dado(/^que estou na tela de Login$/) do
  pending # express the regexp above with the code you wish you had
end

Quando(/^digitar credenciais válidas$/) do
  pending # express the regexp above with the code you wish you had
end

Quando(/^clicar no botão de login$/) do
  pending # express the regexp above with the code you wish you had
end

Então(/^devo acessar a Home do sistema$/) do
  pending # express the regexp above with the code you wish you had
end

Quando(/^digitar credenciais inválidas$/) do
  pending # express the regexp above with the code you wish you had
end

Quando(/^clicar no botão login$/) do
  pending # express the regexp above with the code you wish you had
end

Então(/^devo ver uma mensagem de erro$/) do
  pending # express the regexp above with the code you wish you had
end

Então(/^devo estar na tela de Login$/) do
  pending # express the regexp above with the code you wish you had
end

Neste caso, o Cucumber analisou o nosso arquivo de funcionalidades e, de acordo com os passos encontrados, sugeriu qual seria a melhor expressão regular para identificar esses passos. Sendo assim, não é necessário se preocupar em entender a fundo como funcionam expressões regulares, visto que o Cucumber facilitará bastante na hora de gerar os comandos que interpretarão os passos do arquivo de funcionalidades.

Para completar o fluxo desse teste, precisamos fornecer comandos aos passos. Esses comandos serão responsáveis por fornecer informações e avaliar o comportamento da aplicação testada, verificando se o comportamento é adequado ou não. Um exemplo de um passo seria:

Então(/^devo ver uma mensagem de erro$/) do
  raise "Mensagem de erro não encontrada!" unless @page.contem? "Mensagem de erro"
end

A exceção “Mensagem de erro não encontrada!” será lançada sempre que a mensagem “Mensagem de erro” não estiver presente em uma página @page. A função contem? foi implementada para procurar pela string, passada como parâmetro, dentro do texto da página @page e retornar true, se encontrar, e false, caso contrário.

Com isso fechamos um exemplo simples e incompleto. A ideia foi fornecer uma visão geral de BDD e Cucumber. Diversas informações, tutoriais e exemplos podem ser encontrados na wiki do Cucumber. Nos próximos artigos dessa série, vou apresentar exemplos completos de testes em aplicativos Android e iOS.

Instalação do Cucumber

Para instalar o Cucumber, primeiro você precisará ter o Ruby instalado. Para isso, sugiro a utilização de algum gerenciador de versões como o RVM ou o rbenv. Para instalar o Ruby com o RVM execute os seguintes comandos, retirados desta página:

    gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
    \curl -sSL https://get.rvm.io | bash -s stable --ruby

Após a execução desses comandos você terá uma versão estável da RVM e do Ruby instalada. Um problema que pode acontecer depois da instalação: quando você reiniciar a sua sessão do terminal, você pode perder as referências à RVM e, com isso, seu computador não reconhecerá mais que você está com o Ruby instalado. Para testar se esse problema ocorre, abra um novo terminal e digite ruby -v. Se a resposta do comando for a versão instalada do Ruby, então esse problema não aconteceu e você pode pular os passos seguintes. Porém, se você recebeu um erro de Ruby não instalado, coloque as seguintes linhas no seu arquivo ~/.bash_profile

export PATH="$PATH:$HOME/.rvm/bin" # Add RVM to PATH for scripting
[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm

Abra uma nova sessão do terminal e digite novamente ruby -v. Muito provavelmente, você receberá como retorno a versão do Ruby instalada.

Com o Ruby instalado, vamos instalar o Cucumber. Para isso, execute o comando abaixo:

gem install cucumber

Agora que tudo está instalado, você já pode começar a escrever os seus testes.

Calabash

O Calabash permite a execução dos testes escritos em Cucumber em dispositivos móveis e emuladores/simuladores, tanto para Android quanto iOS. Três gems compõem o seu ambiente: calabash-common, calabash-cucumber (iOS) e calabash-android. Essas gems, além de permitirem que os testes escritos em Cucumber sejam executados em dispositivos móveis, também disponibilizam diversas funções que facilitam a realização de gestos e asserções.

Por exemplo, existem diversos passos, chamados pelos criadores do Calabash de “Canned Steps” no caso do Android e “Predefined steps” no caso do iOS, que permitem que você realize diversas ações somente escrevendo-os nos arquivos de funcionalidades, sem a necessidade de implementar um passo. Se você escrever Then I go back ou When I go back, o Calabash irá realizar um click no botão de voltar de um dispositivo Android. Vale lembrar que esses passos foram criados pelos desenvolvedores das gems do Calabash e, portanto, estão todos em inglês.

Devido às diferenças nas plataformas, a estrutura do Calabash também possui algumas diferenças quando utilizado para Android e para iOS. A arquitetura do Calabash Android pode ser vista na figura abaixo. Existem duas entidades: i) o computador no qual os testes foram escritos e que controla a execução dos testes e; ii) o dispositivo/emulador que irá rodar os testes.

Extraída de: http://blog.lesspainful.com/2012/03/07/Calabash-Android/
Extraída de: http://blog.lesspainful.com/2012/03/07/Calabash-Android/

Dentro do computador ficam os arquivos de funcionalidades, os passos e a biblioteca Ruby responsável por traduzir os passos em ações a serem executadas no dispositivo/emulador. Para executar os testes não é necessário realizar nenhuma alteração em seu aplicativo, pois o Calabash irá instalar junto a ele um servidor de testes, que receberá os comandos da biblioteca Ruby e executará os passos no dispositivo/emulador com a ajuda do “Instrumentation” do Android.

No caso do iOS, a arquitetura é um pouco diferente. Como podemos ver na figura abaixo, extraída desse post, existem as mesmas duas entidades, porém o servidor de testes está embutido no aplicativo. No caso do iOS, o Calabash necessita que seu aplicativo seja alterado para conter esse servidor. Isso ocorre por meio de um comando de configuração, que cria um novo “target” para o aplicativo. Ao executar esse “target”, o Calabash iniciará junto com o aplicativo um servidor HTTP, que receberá as solicitações de execução de comandos da biblioteca Ruby, que por sua vez executa no computador. Esse servidor é responsável, então, por traduzir essas solicitações em comandos a serem executados pelo “Instruments” do iOS.

Extraída de: http://blog.lesspainful.com/2012/03/07/Calabash-iOS/
Extraída de: http://blog.lesspainful.com/2012/03/07/Calabash-iOS/

Aconselho uma leitura atenta dos dois links anteriores para um bom entendimento da arquitetura. Esse conhecimento será muito importante ao “debugar” a execução dos testes, principalmente no iOS, que apresenta uma média maior de erros durante a configuração inicial do sistema.

E é isso! Espero ter conseguido apresentar as principais características, tecnologias e ferramentas utilizadas para os testes. Aconselho fortemente a instalação do Ruby, execução de um tutorial que utilize o Cucumber e a leitura dos posts da arquitetura do Calabash. Essas informações serão importantes para facilitar o entendimento dos nossos próximos posts. Na próxima semana, pretendo falar sobre como automatizar testes no Android com o Calabash.

Se você tiver dúvidas, sugestões ou qualquer consideração, é só deixar no campo abaixo. Até a próxima!