IceCream e a fábrica de testes inteligente

Sim! Existe uma forma inteligente de juntar as palavras “Fábrica” e “Teste”. Obviamente, o título é um trocadilho, mas o conceito deste post é bem interessante, principalmente para quem usa webdriver ou outro framework de automação baseado em Ruby.

A bastante tempo tenho usado Factory-Girl como factory para fazer meus testes, mas na maioria das vezes a applicação era baseada em Rails, Sinatra ou algo semelhante, que facilitava o uso dessa rubygem. Mas algumas vezes em que eu estava usando ruby para fazer testes blackbox com Selenium, Watir ou Cello, onde de nenhuma forma o aplicativo interno me interessava, e por isso eu tinha que fazer muitas gambiarras para conseguir usar essa ou outra gem para fabricar objetos de teste. Depois de procurar por bastante tempo por uma solução agnostica de implementação, frameworks e sem dependências, eu resolvi montar a minha própria rubygem, e assim nasceu, em dois dias, o IceCream (https://github.com/camiloribeiro/icecream).

Como as minhas outras gems/projetos, o nome faz uma analogia que reflete o meu péssimo senso de humor. Mas vamos falar sobre isso mais a frente. Primeiro, vamos entender o que é um Factory e como ele pode nos ajudar a testar com menos esforço, menos código, mais reuso e mais flexibilidade.

O conceito

Factory é um padrão de projetos (design pattern) originalmente desenhado para linguagens orientadas a objetos, para gerar, de uma maneira simples e prática, objetos de vários tipos baseados em uma única interface, ou seja, você pode pedir a uma entidade um objeto qualquer que ela conheça, e ela vai te retornar esse objeto e seus atributos. Você ainda pode mudar os atributos desse objeto de acordo com as suas necessidades. Encontre outras definições melhores que essa aqui (wikipedia), aqui (JavaWorld) e aqui (devmedia).

Exemplificando com a analogia do IceCream, vamos imaginar que temos um freezer. Esse freezer contém um estoque infinito de dezenas ou centenas de sabores diferentes de sorvete. Sempre que precisamos de um sabor diferente, podemos ir ao freezer e pedir um novo sorvete. :)

Mas onde isso se aplica nos meus testes?

Formulário simples de cadastro de sorvete
Formulário simples de cadastro de sorvete

Vamos imaginar que estamos testando o cadastro de sorvetes de uma sorveteria. Para isso, vamos usar o formulário a nossa esquerda. Vamos escrever, de uma maneira bem superficial, alguns casos de teste que podemos identificar baseado somente nesse formulário:

  • Cadastrar um sabor com todas as informações;
  • Cadastrar um sabor só com os campos obrigatórios;
  • Cadastrar um Sorvete com cada opção especial “Light”, “Diet” e “Cheio de Açucar”;
  • Tentar cadastrar um sabor sem cada um dos campos obrigatórios “Sabor do Sorvete”, “Preço” e “Coloração”;
  • Cadastrar um Sorvete com cada uma das cores;
  • Um sorvete com preço quebrado (com centavos);
  • Tentar cadastrar um sabor sem o campo obrigatório com letras no preço;
  • Etc.

Todos esses são casos de teste que um testador pensaria na etapa de planejamento dos testes. Cada um vai descrever esses casos de uma maneira, desde os mais tradicionais com artefatos ou documentos para cada caso, até os mais flexiveis como eu, que vai ter um bloco de notas com algumas ideias ou alguns rabiscos em um rascunho velho.

Quando vamos automatizar esses testes, começamos a notar uma coisa interessante. Vamos imaginar que escrevemos um script em uma linguagem qualquer, que ficaria mais ou menos assim:

Go To PaginaCadastroSorvetes
Set "Sabor do Sorvete" = "Chocolate"
Set "Preço" = 15
Set "Calorías" = 150
Set "Descrição" = "Chocolate belga, com amendoas"
Select "Especial" = "Cheio de Açucar"
Select "Coloração" = "Marrom"
PaginaCadastroSorvetes.Submit()
ConfereResposta "Sorvete Cadastrado com Sucesso"

Eis que temos o nosso primeiro caso de testes automatizado :D

Agora vamos automatizar o próximo, que é o caso de um sabor só com os campos obrigatórios:

Go To PaginaCadastroSorvetes
Set "Sabor do Sorvete" = "Chocolate"
Set "Preço" = 15
Set "Calorías" = 150
Set "Descrição" = ""
Select "Especial" = ""
Select "Coloração" = ""
PaginaCadastroSorvetes.Submit()
ConfereResposta "Sorvete Cadastrado com Sucesso"

Yeya! Segundo caso de teste automatizado, agora só faltam… 42 :(

O exemplo acima, embora bem simples, reflete a realidade de muitas codebases de teste automatizado, especialmente das codebases geradas por ferramentas de record and replay (aquelas que gravam o script). Os problemas dessa forma de escrever testes não são poucos, entre eles o fatode ser muito muito cansativo de escrever e de ser quase impossível manter conforme mudanças vão sendo necessárias.

ps: Caso se interesse em saber mais sobre como evitar repetição, leia “Penso, logo automatizo” deste mesmo blog.

O Exemplo

Vamos pensar de outra forma agora, vimos que o “cenário” quase sempre é o mesmo. Abrir a página, preencher (ou não) os campos, submeter para o servidor e conferir a resposta. Vamos implementar um pouco de factory agora em dois modelos

O primeiro, consiste em ter os sabores de teste já definidos em algum outro lugar, por exemplo em um arquivo de dados de teste. Dessa forma podemos iterar sobre todos os sorvetes de uma forma bem limpa:

// Pegamos todos os sorvetes e colocamos em uma lista
TodosOsSorvetes = Get TodosOsSorvetes
/* 
* Para cada sorvete cadastrado fazemos um 
* for e colocamos o valor em uma variavel chamada Sorvete
*/
TodosOsSorvetes.ItereCada Sorvete
  Go To PaginaCadastroSorvetes
  Set "Sabor do Sorvete" = Sorvete.GetSabor
  Set "Preço" = Sorvete.GetPreço
  Set "Calorías" = Sorvete.Getcalorias
  Set "Descrição" = Sorvete.GetDescrição
  Select "Especial" = Sorvete.GetEspecial
  Select "Coloração" = Sorvete.GetColocação
  PaginaCadastroSorvetes.Submit()
  ConfereResposta  = Sorvete.GetResposta
IteraProximoSorvete

Uma segunda forma de fazer isso, é mudando o valor dos atributos do sorvete na hora de usar, o que permite uma fexibilidade bem grade para manutenção do código de testes. Vamos imaginar que temos um sorvete de chocolate, e agora queremos testar exatamente o mesmo sabor, mas vamos mudar de “Cheio de Açucar” para “Diet”:

// Pegamos o sorvete precadastrado Chocolate
chocolate = Get :Chocolate

// Agora mudaos o sabor do objeto, sem afetar os demais items
chocolate.setEspecial = "Diet"

Go To PaginaCadastroSorvetes
Set "Sabor do Sorvete" = chocolate.GetSabor
Set "Preço" = chocolate.GetPreço
Set "Calorías" = chocolate.Getcalorias
Set "Descrição" = chocolate.GetDescrição
Select "Especial" = chocolate.GetEspecial
Select "Coloração" = chocolate.GetColocação
PaginaCadastroSorvetes.Submit()
ConfereResposta  = "Sorvete Diet Cadastrado"

Agora você pode estar pensando: “Nossa, mas falando assim até parece fácil… Na realidade deve ter que fazer um monte de codigo e deve ficar muito complicado :(“. Por isso vou mostrar um exemplo em ruby usando IceCream.

Ná Prática com IceCream

Primeiro, como tudo em ruby, vamos seguir duas convenções. A primeira é o nome do diretório que deve ser “flavors” (sabores no plural) e segundo, a extensão do arquivo que deve ser “.flavor” (sabor no singular). Para cada sabor de sorvete, vamos criar um arquivo texto, dentro da pasta “flavors” com a extensão “.flavor”. Vamos imaginar que o nosso sorvete inicial é o de chocolate:

nomeSabor = "Chocolate"
preco = 15.5
calorías = 150
descricao = "Muit gostoso >D"
especial = :diet
colocacao = :marrom

Agora, dentro dos nossos testes, vamos incluir um require, e criar um “freezer”:

require "icecream"

saboresPreferidos = IceCream::IceCream.new "/caminho/para/pasta/flavors"

chocolate = saboresPreferidos.flavor :chocolate

Pronto! Você tem um objeto da classe “Chocolate”, com todos os atributos e valores definidos no arquivo de texto.

Se quiser pegar o valor de algum atributo basta puxar o valor do próprio objeto (exemplo abaixo):

chocolate.calorias
retorna -> 150                    # =( muitas calorías

Mas se quiser mudar qualquer valor, por qualquer outra coisa, pode usar a atribuição também no próprio objeto (exemplo abaixo):

chocolate.calorias = 0
chocolate.calorias
agora retorna -> 0                # =D Eba! Zero Calorías!

Para conhecer melhor a gem, eu recomendo forkar o projeto e ler os testes, ou instalar ela no seu computador e rodar, pode ser usando o terminal mesmo e não importa qual o seu sistema operacional, para aprender leia “Aprendendo automação sem cursos caros” , e depois postar as dúvidas e sugestões nos comentários :)

Caso tenha interesse em outras gems, conheça a já citada Factory-girl ou outras listadas no ruby-toolbox.

Bons testes!

Camilo Ribeiro

Test Engineer at Klarna
Desenvolvedor, testador e agilista desde 2005, atualmente trabalhando na Suécia.

Leave a Reply