Introdução ao Teste iOS Com Automação UI
Pois imagina ser capaz de escrever scripts que interagem automaticamente com a sua aplicação iOS e ser capaz de verificar os resultados. Com a UI Automation você pode. Automação de IU é uma ferramenta fornecida pela Apple para realizar um nível mais alto de testes em sua aplicação iOS além de qualquer coisa alcançável com XCTest.
1. White Box versus Black Box Testing
Você pode ter ouvido a comparação de testes de caixas brancas versus testes de caixas pretas com relação a como se pode testar uma peça de software. Se você não está familiarizado com estes conceitos, deixe-me explicar como eles funcionam.
White Box Testing
Imagine que há um pedaço de software rodando dentro de uma caixa. Com o teste da caixa branca, você pode ver dentro da caixa e olhar para todos os pedaços de areia de como o software funciona, e então tomar decisões educadas sobre como testar o software. Você também pode ter ganchos de nível mais profundo dentro do software a partir dos testes que você escreve.
Unit testing is white box testing. Ao escrever testes unitários, o testador tem acesso ao código em teste. O testador pode realmente escrever testes que alavancam o software em teste no método, ou unidade, nível.
No desenvolvimento de software iOS usamos o framework XCTest para realizar este tipo de teste. Dê uma olhada em outro tutorial que escrevi sobre como começar com o XCTest.
Black Box Testing
Em teste de caixa preta, a caixa é opaca. O testador não consegue ver dentro da caixa. O testador não pode acessar e não sabe sobre a implementação da base de código para escrever testes. Ao invés disso, o testador é forçado a usar o aplicativo como um usuário final, interagindo com o aplicativo e aguardando sua resposta, verificando os resultados.
Existem pelo menos duas formas de executar este tipo de teste.
- Um testador que repetidamente e manualmente executa uma série de passos pré-definidos e verifica visualmente os resultados.
- Utilizar ferramentas especializadas para testar a aplicação com APIs que se comportam de forma similar à interação humana.
No desenvolvimento da aplicação iOS, a Apple fornece uma ferramenta chamada UI Automation para realizar testes com caixa preta.
2. O que é Automação de IU?
UI Automation é uma ferramenta que a Apple fornece e mantém para testes de nível superior, automatizados, de aplicações iOS. Os testes são escritos em JavaScript, aderindo a uma API definida pela Apple.
Testes de escrita podem ser facilitados confiando em etiquetas de acessibilidade para elementos de interface do usuário em sua aplicação. Mas não se preocupe, se você não tiver estes definidos, há alternativas disponíveis.
A API de automação da UI carece do típico formato baseado em xUnit para escrita de testes. Uma diferença com os testes unitários é que o testador precisa registrar manualmente o sucesso e as falhas. Os testes de automação da IU são executados a partir do instrumento de automação dentro da ferramenta Instrumentos que vem com as ferramentas de desenvolvimento da Apple. Os testes podem ser executados no Simulador iOS ou em um dispositivo físico.
3. Escrevendo Testes de Automação de IU
Passo 1: Abra o Projeto Amostra
Atualizei o projeto amostra usado no tutorial anterior sobre testes iOS com alguns elementos adicionais de interface com o usuário que fornecem alguns ganchos úteis para adicionar testes de Automação de IU. Baixe o projeto a partir do GitHub. Abra o projeto e execute o aplicativo para ter certeza de que tudo está funcionando como esperado. Você deve ver uma interface de usuário similar à mostrada abaixo.
Antes de escrever qualquer teste, sinta-se livre para experimentar a aplicação de exemplo para se familiarizar com sua funcionalidade. Como usuário, você pode inserir texto no campo de texto e tocar no botão para ver uma etiqueta na tela que exibe a string invertida, inserida.
Passo 2: Criar um teste de automação da IU
Agora que você esteja familiarizado com a aplicação de amostra, é hora de adicionar um teste de automação da IU. Automação de IU é uma ferramenta que pode ser encontrada em Instrumentos. Para executar a aplicação de amostra em Instruments, selecione Produto > Profile no menu do Xcode. Selecione Automação na lista de ferramentas.
A janela principal de Instrumentos será aberta com um único instrumento pronto para rodar, o Instrumento de Automação (o Instrumento de Automação executa os casos de teste da IU Automação). Você também verá uma área na metade inferior da janela que se parece com um editor de texto. Este é o editor de scripts. Aqui é onde você vai escrever seus testes de Automação de IU. Para este primeiro teste, siga as instruções abaixo, adicionando cada linha ao script no editor de scripts.
Inicie armazenando uma referência ao campo de texto em uma variável.
var inputField = target.frontMostApp().mainWindow().textFields();
Definir o valor do campo de texto.
inputField.setValue("hi");
Verifiquem se o valor foi definido com sucesso e, se foi, passem no teste. Falhe o teste se não tiver sido.
Embora este teste seja bastante trivial, ele tem valor. Acabamos de escrever um teste que testa a presença de um campo de texto quando a aplicação é iniciada e que testa se uma string aleatória pode ser definida como o valor do campo de texto. Se você não acredita em mim, então remova o campo de texto do storyboard e execute o teste. Você verá que ele falha.
Este teste demonstra três partes importantes da escrita de testes de automação da interface de usuário. Primeiro, ele mostra como acessar um elemento simples da interface do usuário, o campo de texto. Especificamente, acessamos um dicionário de todos os campos de texto na vista base da aplicação via target.frontMostApp().mainWindow().textFields()
e depois encontramos o campo de texto que nos interessa, procurando aquele com a chave Input Field
. Esta chave é na verdade a etiqueta de acessibilidade do campo de texto. Neste caso, ela está definida no storyboard. Também podemos definir a etiqueta de acessibilidade em código usando a propriedade accessibilityLabel
em NSObject
.
Acessando a janela principal da aplicação, a aplicação mais frontal, e o alvo são comuns quando se trabalha com a UI Automation. Mostrarei como tornar isto mais fácil e menos verboso mais tarde neste tutorial.
Segundo, isto mostra que você pode interagir com os elementos da interface do usuário na tela. Neste caso, definimos o valor do campo de texto, imitando o usuário interagindo com a aplicação, inserindo o texto no campo de texto.
E terceiro, o exemplo também mostra uma técnica para verificar o que acontece na aplicação. Se o valor for definido com sucesso, o teste passa. Se o valor não for definido, o teste falha.
Passo 3: Salvando Testes
Embora escrever testes no editor de scripts seja conveniente, ele rapidamente se torna incômodo e difícil de manter. Se você sair de Instrumentos, quaisquer alterações não salvas são descartadas. Nós precisamos salvar os testes que escrevemos. Simplesmente copie e cole seu teste em um novo documento em seu editor de texto favorito e salve-o. Você pode encontrar os testes criados neste tutorial no projeto modelo em Jumblify/JumblifyTests/AutomationTests.js.
Para executar o teste, selecione a aba do meio no painel à direita, ao lado do editor de scripts, e selecione Add > Importar.
Você será solicitado a selecionar o script a ser importado. Navegue até o script salvo e importe-o. Você ainda pode alterar o script no editor de scripts. Quaisquer alterações serão automaticamente salvas no arquivo externo que você criou.
Passo 4: Toque em um botão
Passamos a atualizar nosso teste para testar a interação com o botão. O nosso teste já adiciona texto ao campo de texto, por isso só precisamos de adicionar código para tocar no botão. Vamos primeiro considerar como encontrar o botão na vista para que ele possa ser tocado. Existem pelo menos três formas de conseguir isto e cada abordagem tem as suas contrapartidas.
Aplicação 1
Podemos programar uma coordenada (X, Y) na tela. Fazemos isso com a seguinte linha de código:
target.tap({x: 8.00, y: 50.00});
Obviamente, não tenho ideia se essas são mesmo as coordenadas do botão na tela e não vou me preocupar com isso, porque esta abordagem não é a ferramenta certa para este trabalho. Só estou mencionando para que você saiba que ela existe. Usando o método tap
em target
para tocar num botão é susceptível de erro, porque esse botão pode não estar sempre nessa coordenada específica.
Aproximação 2
Também é possível encontrar o botão pesquisando a matriz de botões da janela principal, semelhante a como acedemos ao campo de texto no primeiro teste. Ao invés de acessar o botão diretamente usando uma chave, podemos recuperar um array de botões na janela principal e codificar um índice de array para obter uma referência ao botão.
target.frontMostApp().mainWindow().buttons().tap();
Esta abordagem é um pouco melhor. Nós não estamos codificando uma coordenada, mas estamos codificando um array index para encontrar o botão. Se por acaso adicionarmos outro botão na página, ele pode acidentalmente quebrar este teste.
Aproximação 3
Isto me leva à terceira maneira de encontrar o botão na página, usando rótulos de acessibilidade. Usando uma etiqueta de acessibilidade, podemos acessar diretamente o botão que gostamos de encontrar um objeto em um dicionário usando uma chave.
target.frontMostApp().mainWindow().buttons().tap();
No entanto, se você adicionar a linha acima ao script e executá-lo, você receberá um erro.
Isso porque ainda não definimos a etiqueta de acessibilidade para o botão. Para fazer isso, vire para o Xcode e abra o storyboard do projeto. Encontre o botão na visualização e abra o Inspetor de Identidade à direita (View > Utilities > Identity Inspector). Certifique-se de que a Acessibilidade está habilitada e defina o Label do botão para Jumblify Button.
Para executar o teste novamente, você precisará executar a aplicação do Xcode selecionando Product > Run e então fazer o perfil da aplicação novamente selecionando Product > Profile. Isto executa os testes e cada teste deve passar agora.
Passo 5: Verifique a String Saltada
Como mencionei anteriormente, a nossa aplicação toma uma string de texto como entrada, e, quando o utilizador toca no botão, mostra a string invertida. Nós precisamos adicionar mais um teste para verificar se a string de entrada está devidamente invertida. Para verificar se a UILabel
está preenchida com a string correta, precisamos descobrir como referenciar a UILabel
e verificar a string que ela exibe. Este é um problema comum ao escrever testes de automação, ou seja, descobrir como referenciar um elemento na aplicação para fazer uma afirmação sobre ele.
Existe um método em quase todos os objetos da API de automação da interface de usuário, logElementTree
. Este método registra os elementos aninhados de um dado elemento. Isto é muito útil para entender a hierarquia de elementos na aplicação e ajuda a descobrir como direcionar um elemento específico.
Vejamos como isto funciona ao registrar a árvore de elementos da janela principal. Dê uma olhada na seguinte linha de código.
target.frontMostApp().mainWindow().logElementTree();
Adicionando esta linha aos resultados do script de teste na seguinte saída:
Como você pode ver, há um subelemento UIAStaticText
do UIAWindow
e você também pode ver que ele tem um nome de ih
, que também acontece ser a string invertida que precisamos verificar. Agora, para completar nosso teste, só precisamos adicionar código para acessar esse elemento e verificar se ele está presente.
Por que só precisamos verificar se o elemento UIAStaticText
está presente? Porque o nome do elemento é a string invertida da string de entrada, verificando sua presença confirma que a string foi corretamente invertida. Se o elemento não existe quando referenciado pelo nome – a string invertida – então significa que a string não foi corretamente invertida.
4. Scratching the Surface
Existem tantas outras maneiras que um usuário final pode interagir com um dispositivo iOS enquanto utiliza seu aplicativo. Isto significa que existem muitas outras maneiras que você pode usar a UI Automation para simular essas interações. Ao invés de tentar capturar uma lista abrangente dessas interações, vou direcioná-lo para a documentação de referência da UI Automation.
Para cada tipo de objeto com o qual você pode interagir, você pode ver a lista de métodos disponíveis naquele objeto. Alguns métodos são para recuperar atributos sobre o objeto enquanto outros são para simular interação por toque, tais como flickInsideWithOptions
em UIAWindow
.
Recording a Session
As você tenta testar mais e mais aplicativos complicados com a UI Automation, você vai descobrir que às vezes é bastante tedioso usar repetidamente logElementTree
para encontrar o elemento que você está procurando. Isto também se torna tedioso e complexo para aplicações com uma hierarquia de visualização ou navegação complexa. Nestes casos, você pode usar outro recurso dos instrumentos para registrar um conjunto de interações do usuário. O que é ainda mais legal é que a Instruments gera o código JavaScript da UI Automation que é necessário para reproduzir as interações gravadas. Aqui está como você mesmo pode experimentar.
Em Instruments e com o instrumento de Automação selecionado, procure o botão de gravação na parte inferior da janela.
Se você clicar no botão de gravação, Instruments iniciará uma sessão de gravação como mostrado na captura de tela abaixo.
Instrumentos iniciarão sua aplicação no Simulador iOS e você será capaz de interagir com ele. Os instrumentos irão gerar um script baseado em suas interações em tempo real. Experimente-o. Rode o Simulador iOS, toque em locais aleatórios, faça um gesto de deslize, etc. É uma forma realmente útil de ajudar a explorar as possibilidades da Automação UI.
Anular uma Base de Código Monolítico
Como você provavelmente pode prever, se continuarmos a adicionar mais testes ao arquivo de teste que criamos no mesmo método, ele se tornará rapidamente difícil de manter. O que podemos fazer para evitar que isso aconteça. Nos meus testes, eu faço duas coisas para resolver este problema:
- Um teste para uma função: Isto implica que os testes que escrevemos precisam de estar focados numa peça específica de funcionalidade. Vou até dar-lhe um nome apropriado, como
testEmptyInputField
. - Testes relacionados com o grupo num só ficheiro: Eu também agrupo testes relacionados com o mesmo arquivo. Isso mantém o código em um único arquivo gerenciável. Isto também facilita o teste de partes separadas de funcionalidade, executando os testes em um arquivo específico. Além disso, você pode criar um script mestre no qual você chama as funções ou testes que você agrupou em outros arquivos de teste.
No seguinte trecho de código, nós importamos um arquivo JavaScript e isto torna as funções naquele arquivo JavaScript disponíveis para nós.
>70>
#import "OtherTests.js"
Conclusão
Neste tutorial, você aprendeu o valor dos testes de nível superior e como a Automação da IU pode ajudar a preencher essa lacuna. É outra ferramenta em sua caixa de ferramentas para ajudar a garantir que você envie aplicações confiáveis e robustas.