Testes de Comportamento com Behave, Chrome headless, Selenium e Docker

Rafael Cirolini
Apr 4 · 4 min read

Quando falamos em Entrega Continua (Continuos Delivery) a primeira coisa que vem a mente de qualquer analista de operação é medo. Pelo simples fato de que o objetivo maior do pessoal de Operações (Ops) é manter os sistemas funcionando, objetivo esse conflitante com o pessoal de Desenvolvimento (Dev), que tem como objetivo criar novas funcionalidades, e novas funcionalidades significam novos bugs e problemas que a aplicação pode ter.

A confiança tem que vir de ambos os lados, dividindo responsabilidades pelo sistema. Mas integrar ao pipeline de entrega continua testes de comportamento da aplicação faz com que todos, ops e devs, possam dormir mais tranquilos.

A ideia aqui é demostrar como criar testes de comportamento simulando um usuário comum com um navegador Chrome que vai abrir uma pagina, clicar em botões, preencher formulários e qualquer coisa mais que seja necessária para testar a sua aplicação.

Todo os códigos aqui utilizados estão no repositório do git: https://github.com/cirolini/docker-selenium-chrome-behave

O Dockerfile:

# Usa uma imagem base do python
FROM python# Instala algumas dependencias necessárias
RUN apt-get update &&\
      apt-get -y install wget gnupg2 unzip# ADD Google Chrome Repo
RUN wget https://dl.google.com/linux/linux_signing_key.pub &&\
      apt-key add linux_signing_key.pub &&\
      echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google-chrome.list# Install Chrome
RUN apt-get update &&\
      apt install -y google-chrome-stable# Install chrome driver
RUN wget https://chromedriver.storage.googleapis.com/2.46/chromedriver_linux64.zip &&\
      unzip chromedriver_linux64.zip &&\
      cp chromedriver /usr/sbin/# Install Selenium and Behave
RUN pip install selenium behaveWORKDIR /app
COPY ./features /app/featuresCMD behave

Resumindo, a partir de uma imagem base do Python, instalamos o Chrome e o chromedriver para poder acessar ele a partir do Selenium, e além disso instalamos o Behave e o Selenium.

A organização das pastas do projeto são assim:

$ tree
.
├── Dockerfile
├── README.md
└── features
    ├── environment.py
    ├── google.feature
    └── steps
        └── steps.py2 directories, 5 files

Primeiro vamos criar o arquivo que vai definir os ambientes dos testes, e como o Chrome e o Selenium vão ser inicializados, o arquivo é o enviroment.py:

from selenium import webdriver
import osdef before_all(context):
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        context.browser =          webdriver.Chrome(chrome_options=chrome_options)def after_all(context):
        context.browser.quit()

Nesse arquivo inicializamos o nosso navegador chrome, com a opção headless para que ele suba antes de qualquer execução dos nossos testes, e que ele seja finalizado ao final de todos eles.

Depois criamos os testes em si no modelo BDD, criamos o arquivo google.feature:

Feature: Testing Google Site
  Scenario: visit google and check content
    When visit url "http://www.google.com/"
    Then it should have a tag "html"  Scenario: can find search results
      When visit url "http://wwww.google.com/"
      When field with name "q" is given "Behave"
      Then title becomes "Behave"

Escrevi os testes em inglês mas poderiam estar escritos em qualquer língua. O mais legal dessa parte é que os testes podem ser escritos por qualquer pessoa do time, sendo técnica ou não, o ideal ainda é que esta etapa seja composta por todos.

Aqui foram usadas várias palavras chaves do Behave, como a When e Then, a ideia aqui não é ensinar o Behave, mas sim fazer uma breve descrição da sua capacidade, para aprender como escrever os testes o melhor local é a própria documentação dele: https://behave.readthedocs.io/en/latest/

Vamos criar o steps.py que vai conter o código responsável por executar cada etapa.

import time@when('visit url "{url}"')
def step(context, url):
    context.browser.get(url)@then('it should have a tag "{tag}"')
def step(context, tag):
   assert tag in context.browser.page_source@when('field with name "{selector}" is given "{value}"')
def step(context, selector, value):
    elem = context.browser.find_element_by_name(selector)
    elem.send_keys(value)
    elem.submit()
    time.sleep(5)@then('title becomes "{title}"')
def step(context, title):
    assert title in context.browser.title

Pronto, agora basta executar o container para ver os testes acontecendo:

$ docker build -t docker-behave .
$ docker run docker-behave
Feature: Testing Google Site # features/google.feature:1

  Scenario: visit google and check content  # features/google.feature:2
    When visit url "http://www.google.com/" # features/steps/steps.py:3
    Then it should have a tag "html"        # features/steps/steps.py:7

  Scenario: can find search results            # features/google.feature:7
    When visit url "http://www.google.com/"    # features/steps/steps.py:3
    When field with name "q" is given "Behave" # features/steps/steps.py:12
    Then title becomes "Behave"                # features/steps/steps.py:19

1 feature passed, 0 failed, 0 skipped
2 scenarios passed, 0 failed, 0 skipped
5 steps passed, 0 failed, 0 skipped, 0 undefined
Took 0m10.177s

Bom, a nossa feature foi testada e passou nos dois cenários. Ufa, o google esta funcionando.

Se você usa o Jenkins como ferramenta de entrega continua, o que eu recomendo é que você dentro do seu pipeline, após atualizar o ambiente de preview execute os testes de comportamento antes de prosseguir para produção, um exemplo do Jenkinsfile pode ser visto a seguir:

...
stage "Build and Push"    def customImage = docker.build("${imageName}")
    customImage.push()stage "Deploy to Preview"
    sh "kubectl set image deployment app app=${imageName} --record"
    sh "kubectl rollout status deployment/app"stage "Test Preview"
    docker.image('cirolini/behave').inside() {
        sh 'cd behave && behave'
    }
...

O legal dessa abordagem, é que o código do teste fica dentro do git do projeto, e somente usa a imagem do Behave para poder testar o projeto sem precisar instalar tudo o que é necessário.

Bom, era isso, espero que aproveitem para os próximos projetos.

4