Já falamos sobre Especificação Por Exemplo em outros artigos. Se você não viu, pode acessar a primeira parte da série aqui. Hoje, vamos mostrar como podemos automatizar os testes de interface utilizando as especificações geradas.
Testes automatizados de interface para Web
Existem muitas ferramentas para automatizar testes de interface em aplicações web. A mais famosa delas é o Selenium Webdriver, que é open source e está disponível em muitas linguagens (Java, C#, Python, Ruby, Perl, PHP, JavaScript).
Com o Selenium, você consegue simular as ações dos usuários no browser (escolher opções, clicar em botões, preencher campos, submeter arquivos e muitas outras). Assim, você consegue automatizar o fluxo que o usuário segue dentro da sua aplicação e verificar os outputs (com frameworks de xUnit, por exemplo) para garantir que o resultado obtido é o esperado para aquele fluxo.
Além do Selenium, existem outras ferramentas que permitem usar o mesmo driver (e chamar métodos selenium também) e facilitam bastante a automação dos testes. Em Ruby, temos o Capybara e em Python, o Splinter.
Aqui na Concrete, estamos usando o Capybara + Siteprism (uma DSL bem legal de Page Objects*), além do Cucumber para criar as especificações.
*Para saber mais sobre Page Objects, clique aqui.
Facilitando as coisas com o Magneton
Para automatizar as especificações, contamos com algumas camadas:
- Especificações: camada na qual vão ficar os arquivos .feature com os nossos cenários em linguagem natural
- Steps: onde ficam os passos gerados a partir das features
- Pages: onde ficam os pages objects, encarregados pela manipulação dos elementos
Além disso, precisamos de algumas opções para execução desses testes – por exemplo, escolher em qual browser ou até em que ambiente rodar (você pode ter um ambiente de desenvolvimento e outro de homologação, e é importante conseguir rodar os mesmos testes em ambos).
Para facilitar a geração dessa estrutura e configurações, criamos uma gem chamada Magneton (RubyGems, GitHub).
Configurando seu ambiente
É necessário instalar o Rbenv, que vai te ajudar a administrar diferentes ambientes Ruby na sua máquina. Assim, você consegue trabalhar com diferentes versões sem alterar a instalação default do sistema operacional. Siga os passos indicados na documentação.
Depois disso, instale o bundle, que vai te ajudar na instalação das gems.
Usando o Magneton
Para instalar, basta executar no terminal:
gem install magneton
Lembrete: no README da gem tem várias informações e explicação sobre os comandos.
Para criar seu primeiro projeto:
magneton new ToDoAppTests
E então sua estrutura de testes está pronta:
Agora basta executar:
bundle install
E todas as gems necessárias para esse projeto serão instaladas.
Para criar sua primeira feature, basta utilizar o comando (dentro da pasta criada com o comando anterior):
magneton generate feature ToDo --lang=pt
Para saber tudo que já está implementado na gem, basta olhar o README no GitHub.
Criando sua primeira feature
Dentro do arquivo /specifications/todo.feature gerado no passo anterior, vamos mapear um cenário para a funcionalidade.
Para esse exemplo, estou usando uma aplicação web de ToDos, ou seja, você pode cadastrar vários ToDos com um título e uma descrição. Ela foi feita em Python utilizando Flask e está disponível no meu GitHub.
# language: pt Funcionalidade: Criar um ToDo Contexto: Home do TodoApp Dado que eu esteja na home do TodoApp Cenário: Criar um Todo com nome e descrição Quando eu crio um novo Todo chamado "Teste" com a descrição "Descrição Teste" Então posso visualizar esse Todo na home do TodoApp
Para saber como escrever bons cenários, vale a pena ler:
- Best practices
- https://blog.engineyard.com/2009/15-expert-tips-for-using-cucumber
- https://github.com/strongqa/howitzer/wiki/Cucumber-Best-Practices
- https://spin.atomicobject.com/2011/06/02/never-say-click-good-cucumber-system-testing-practices/
Feito isso, basta executar:
bundle exec cucumber
E o Cucumber vai gerar os steps pra você:
Depois é só copiar e colar no arquivo features/steps_definitions/todo_steps.rb, que vai ficar assim:
######### DADO ######### Dado(/^que eu esteja na home do TodoApp$/) do pending # Write code here that turns the phrase above into concrete actions end ######### QUANDO ######### Quando(/^eu crio um novo Todo chamado "([^"]*)" com a descrição "([^"]*)"$/) do |titulo, descricao| pending # Write code here that turns the phrase above into concrete actions end ######### ENTãO ######### Então(/^posso visualizar esse Todo na home do TodoApp$/) do pending # Write code here that turns the phrase above into concrete actions end
Agora, se você executar novamente:
bundle exec cucumber
A saída do console vai indicar que existe um cenário com 3 passos que precisam ser implementados.
Implementando os cenários
Agora que já sabemos qual o fluxo que o usuário vai seguir, precisamos automatizar os passos para isso.
Nosso page object features/pages/todo_page.rb vai ficar com o seguinte conteúdo, representando a homepage do nosso ToDoApp:
class TodoPage < SitePrism::Page element :btn_novo_todo, '#new' def clicar_btn_novo_todo btn_novo_todo.click CreateTodoPage.new end def get_conteudo_pagina page.html end end
Vamos criar outro page object chamado features/pages/create_todo_page.rb para representar a página na qual criamos os ToDos. Ele vai ter o seguinte conteúdo:
class CreateTodoPage < SitePrism::Page element :input_titulo, '#title' < Você está interpolando? Se sim, não seria #{tittle} ? element :input_descricao, '#text' element :btn_salvar, '#save' def criar_todo(titulo, descricao) input_titulo.set titulo input_descricao.set descricao btn_salvar.click TodoPage.new end end
Feito isso, podemos voltar para os nossos steps e utilizar os métodos que criamos nos page objects para simular as ações do usuário. Nosso arquivo features/steps_definitions/todo_steps.rb vai ficar com o seguinte conteúdo:
######### DADO ######### Dado(/^que eu esteja na home do TodoApp$/) do @home = TodoPage.new @home.visit('http://0.0.0.0:5000/') ## url da aplicacao end ######### QUANDO ######### Quando(/^eu crio um novo Todo chamado "([^"]*)" com a descrição "([^"]*)"$/) do |titulo, descricao| @novo_todo = @home.clicar_btn_novo_todo @home = @novo_todo.criar_todo(titulo, descricao) end ######### ENTãO ######### Então(/^posso visualizar esse Todo na home do TodoApp$/) do atual = @home.get_conteudo_pagina expect(atual).to include("Teste") expect(atual).to include("Descrição Teste") end
Ao rodar novamente:
bundle exec cucumber
A saída do console vai indicar que o cenário e seus 3 steps passaram.
Vídeo da execução – https://goo.gl/brzvYv
Concluindo
Os testes automatizados ajudam muito quando se fala de testes regressivos, imagine testar manualmente esse cenário de Criação de ToDos toda vez que a aplicação tiver uma alteração?
Com nosso teste automatizado, que é executado em 2 segundos, conseguimos garantir que esse cenário sempre será validado, dando segurança na implementação de mudanças.
Pra quem quiser ler mais sobre o tema, tem um repositório meu com explicações detalhadas sobre o Capybara.
Dúvidas? Só comentar aqui!
***
Artigo publicado originalmente em http://www.concretesolutions.com.br/2016/10/26/testes-de-interface-web-em-ruby/.