Back-End

8 nov, 2016

Automatizando testes de interface web em Ruby

Publicidade

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).

image1Sim, é o nome de um Pokemón

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:

image2Estrutura gerada pela gem

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

image3Criado o arquivo de feature, um step e um page object

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.

image4Tela do ToDoApp

# 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:

Feito isso, basta executar:

bundle exec cucumber

E o Cucumber vai gerar os steps pra você:

image5

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.

image6

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.

image7Testes passando \o/

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/.