Índice
- Introdução
1.1 Agradecimentos
1.2 A Solução Docker
- Instalando Docker
3.1 Requisitos Mínimos
3.2 Instalando
- Configurando Docker
4.1 Imagens Docker
4.2 Docker Compose
4.3 Arquivo Yml
4.4 Implementação
- Comandos Docker Compose
5.1 Spin Up Containers
5.2 Checar Containers Criados
5.3 Reiniciar Containers
5.4 Tear Down Containers
- Executar Testes em um Container
6.1 Convenções
6.2 Implementação
6.3 Executar os testes em um container
- Escalar Testes utilizando Containers
7.1 Escalar docker containers
7.2 Executar testes paralelos em um container
1. Introdução
1.1 Agradecimentos
- Esse tutorial foi criado com base no curso “Scaling Tests with Docker” por Carlos Kidman.
- Curso disponível na “Testing Automation University”.
1.2 A Solução Docker
Ao desenvolver projetos de automação de testes surgem dois principais problemas:
- Testes UI são lentos e demoram muito tempo para executar.
- Variáveis externas como as de ambiente podem criar testes quebradiços.
Vamos utilizar o Docker para resolver isso.
2. O Que é Docker
Com docker você pode “buildar” e compartilhar containers e automatizar o “pipeline” de desenvolvimento a partir de um único ambiente.
Cada um desses containers representa um pedaço do app ou do sistema.
Imagens (“Blueprints”):
- Assim como as imagens para VMs, especificações de imagens docker são utilizadas para criar containers.
Containers:
- Permite que você “empacote” as coisas que você precisa.
- São mais rápidas e leves que as máquinas virtuais.
Nesse tutorial nós utilizaremos versões de imagens do Chrome e do Firefox e uma imagem “Selenium Grid” para subir a quantidade de containers que precisarmos.
Com alguns comandos simples nós faremos o “spin up”, “restart” e “tear down” de um grid completo em segundos.
3. Instalando Docker
3.1 Requisitos Mínimos
Antes de você começar a instalar o docker verifique se você habilitou a virtualização:
Habilitar virtualização pela BIOS no windows.
3.2 Instalando
Clique no link abaixo para escolher a versão do docker que você queira instalar, nesse tutorial irei mostrar como instalar a versão para o windows:
https://docs.docker.com/get-docker/.
Etapa 1 – Escolha a versão para o windows.
Etapa 2 – Faça o download.
Etapa 3 – Selecione pelo menos a opção “WSL 2” e clique OK.
Etapa 4 – Clique no botão “Close and restart” para reiniciar sua máquina.
Etapa 5 – Marque a opção “I accept the terms” e clique em “Accept”.
Etapa 6 – Se a mensagem da imagem abaixo for exibida para você, vá para o link abaixo e instale a atualização wsl para o windows.
Pacote de atualização do kernel do Linux do WSL2 para computadores x64.
Após instalado clique em “Restart”.
Etapa 7 – O docker engine está rodando e pronto para uso.
Etapa 8 – Para verificar se o docker foi instalado com sucesso abra o “Prompt de Comando” e execute o comando abaixo.
docker version
4. Configurando Docker
A imagem abaixo representa a estrutura do projeto.
Na configuração do nosso grid existem 3 principais peças:
- Docker Engine (“My Laptop”).
- Hub Container (Um dos nodes do selenium grid)
- Node containers (Os navegadores conectados ao hub).
Os testes serão executados apontando para o hub que irá fazer o balanceamento entre os nodes.
O hub e os nodes são containers, para criar containers você precisa de imagens docker.
4.1 Imagens Docker
Para baixar as imagens docker vá para docker hub, esse site é um repositório de imagens docker onde você pode salvar e/ou baixar imagens.
Para baixar as imagens é necessário que você tenha criado uma conta.
Após criar uma conta prossiga para fazer o login.
Após o login pesquise por “selenium”:
Pesquise pelos nodes disponibilizados pelo selenium, então baixe os seguintes:
- selenium/hub
- selenium/node-chrome
- selenium/node-firefox
Para baixar cada uma das imagens docker clique nelas, copie o comando do campo “Docker Pull Command”, cole no seu “Prompt de Comando” e confirme.
docker pull selenium/hub
Repita o processo “docker pull” para as outras 2 imagens listadas anteriormente.
docker pull selenium/node-chrome
docker pull selenium/node-firefox
Para verificar se as imagens foram baixadas com sucesso execute o comando abaixo:
docker images
4.2 Docker Compose
Para criar um container de cada vez você precisa de utilizar o comando “docker run”.
Em nosso tutorial iremos criar todos os nossos containers de uma só vez com apenas um comando utilizando docker compose “yml”.
Docker compose é uma parte do docker que possui seus próprios comandos e utiliza um arquivo “yml” para descrever as especificações dos containers.
Docker compose define um único arquivo “yml” com os serviços (containers) que você quer, então usa o comando “docker-compose” para criá-los de uma só vez.
4.3 Arquivo Yml
Para configurar um arquivo “docker-compose.yml” nós iremos utilizar o repositório do tutorial anterior:
https://github.com/LuizGustavoR/intro-selenium-py/tree/tutorial/parallel-tests
(branch: tutorial/parallel-tests).
Clone na sua máquina e abra o projeto utilizando o VS Code.
É ok criar o arquivo “docker-compose.yml” em qualquer lugar do projeto,
mas nesse tutorial colocaremos ele dentro de uma pasta chamada “docker”.
“docker/docker-compose.yml”:
4.4 Implementação
version: "3"
services:
selenium-hub:
image: selenium/hub
container_name: selenium-hub
ports:
- "4444:4444"
chrome:
image: selenium/node-chrome
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4444
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
- SE_NODE_MAX_SESSIONS=3
firefox:
image: selenium/node-firefox
shm_size: 2gb
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4444
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_OVERRIDE_MAX_SESSIONS=true
- SE_NODE_MAX_SESSIONS=4
Para mais informações sobre como o docker-compose funciona visite:
https://github.com/SeleniumHQ/docker-selenium
5. Comandos Docker Compose
Abra o “Prompt de Comando” dentro do diretório que você salvou o arquivo “docker-compose.yml”:
5.1 Spin Up Containers
Para executar as imagens e criar os containers execute o comando abaixo:
docker-compose up -d
Para listar os containers criados execute o comando abaixo:
docker ps -a
5.2 Checar Containers Criados
Você pode verificar se os containers foram criados acessando a url abaixo:
http://localhost:4444/
Você também pode verificar os containers que você criou utilizando a versão desktop do docker que você instalou na sua máquina.
5.3 Reiniciar Containers
Para reiniciar o grid execute o comando abaixo:
docker-compose restart
5.4 Tear Down Containers
Para “derrubar” o grid execute o comando abaixo:
docker-compose down
Para verificar se os containers foram “derrubados” execute o comando abaixo:
docker ps -a
Obs.: Tear Down = Derrubar.
6. Executar Testes em um Container
6.1 Convenções
Como discutido no tutorial “Testes em Paralelo”, para executar testes em paralelo (e escalá-los) você precisará:
- Executar testes independentemente.
- Testes não compartilham um driver (webdriver).
Dica:
- Lembre-se de reportar os resultados dos testes na máquina em que o “Docker Engine” esteja sendo executado (no caso deste tutorial a sua máquina).
- O nome do arquivo de cada relatório tem que ser único para que eles não sejam sobrescritos.
Obs.: Relatório de bugs não será implementado neste tutorial.
6.2 Implementação
Para executar o projeto em um docker container é necessário editar 3 arquivos em nosso projeto:
- docker-compose.yml (Já foi editado no capítulo “4.4 Implementação”).
- config.json
- conftest.py
“config.json”:
{
"browser": "Headless Chrome",
"type": "remote",
"implicit_wait": 10,
"url_remote": "http://127.0.0.1:4444/wd/hub"
}
“conftest.py”:
"""
This module contains shared fixture.
"""
import json
import pytest
import selenium.webdriver
# scope='session' makes
# this fixture run only one time before the entire test suite
@pytest.fixture
def config(scope='session'):
# Read the file
with open('config.json') as config_file:
config = json.load(config_file)
# Accept values are acceptable
assert config['browser'] in ['Firefox', 'Chrome', 'Headless Firefox', 'Headless Chrome']
assert config['type'] in ['local', 'remote']
assert isinstance(config['implicit_wait'], int)
assert config['implicit_wait'] > 0
assert isinstance(config['url_remote'], str)
assert len(config['url_remote']) > 0
# Return config so it can be used
return config
# This fixture will run once for each test case
@pytest.fixture
def browser(config):
# Initialize the local WebDriver instance
if config['type'] == 'local':
if config['browser'] == 'Firefox':
b = selenium.webdriver.Firefox()
opts.add_argument('--window-size=1920,1080')
b = selenium.webdriver.Firefox(options=opts)
elif config['browser'] == 'Chrome':
opts = selenium.webdriver.ChromeOptions()
opts.add_argument('--window-size=1920,1080')
b = selenium.webdriver.Chrome(options=opts)
else:
raise Exception(f'Browser "{config["browser"]}" is not supported in local mode')
# Initialize the remote WebDriver instance
elif config['type'] == 'remote':
if config['browser'] == 'Headless Firefox':
opts = selenium.webdriver.FirefoxOptions()
elif config['browser'] == 'Headless Chrome':
opts = selenium.webdriver.ChromeOptions()
else:
raise Exception(f'Browser "{config["browser"]}" is not supported in remote mode')
opts.add_argument('--no-sandbox')
opts.add_argument('--headless')
opts.add_argument('--disable-gpu')
b = selenium.webdriver.Remote(
command_executor = config['url_remote'],
options=opts
)
# Make its calls wait for elements to appear
b.implicitly_wait(config['implicit_wait'])
# Return the WebDriver instance for the setup
yield b
# Quit the WebDriver instance for the instance
b.quit
6.3 Executar os testes em um container
Antes de começar, verifique se já existem containers rodando na sua máquina executando o comando abaixo:
docker ps -a
Nenhum container sendo executado:
Obs.: Se você encontrar algum container em execução, derrube-o executando o comando abaixo dentro da pasta “docker” do projeto:
docker-compose down
“spin up” (suba) os novos containers do grid:
docker-compose up -d
Containers em execução:
Retorne da pasta “docker” para a raíz do seu projeto executando o comando “cd..”:
Quando dentro da raíz do seu projeto, para executar os testes dentro do container do docker execute o comando abaixo:
pipenv run python -m pytest
Os 3 testes irão executar cada um em um sessão do chrome container:
Perceba que após um teste é finalizado (quit), demora um tempo para o container limpar a sessão.
Então um novo teste não irá iniciar já que não existem sessões disponíveis.
Para resolver isso você tem 3 opções:
- Reinicie o grid ao executar o comando “docker-compose restart” dentro da pasta “docker” e então de volta à pasta raiz do projeto execute o comando dos testes novamente.
- Permitir que o chrome container execute mais sessões de teste.
Faça isso ao editar o arquivo “docker-compose.yml”, por exemplo:
Substitua “SE_NODE_MAX_SESSIONS=3” por “SE_NODE_MAX_SESSIONS=6”.
Obs.: Não esqueça de executar dentro da pasta “folder” do projeto o comando “docker-compose up” e “docker-compose down”, o comando “docker-compose restart” não vai atualizar o limite máximo do número de sessões.
- A melhor e terceira opção é “Escalar docker containers”.
Mais detalhes no capítulo abaixo.
7. Escalar Testes utilizando Containers
7.1 Escalar docker containers
Para que você escale por 10 o número de chrome containers que foram declarados no arquivo “docker-compose.yml” vá para a pasta “docker” dentro do projeto e execute o comando abaixo:
docker-compose up -d --scale chrome=10
Agora você possui 10 chrome containers, cada container possuindo um máximo de 3 sessões em execução, resultando em um total de 30 sessões:
7.2 Executar testes paralelos em um container
Caso você queira executar os testes em paralelo igual fizemos no tutorial “Executando Testes em Paralelo” utilizando o xdist, mas em um container, apenas execute o comando abaixo na pasta raíz do projeto:
pipenv run python -m pytest -n 3
Como você pode ver o selenium grid distribuiu a carga de teste, redirecionando cada teste para executar em um único container entre os 10 que escalamos acima:
Para “derrubar” tudo de uma vez execute o comando abaixo na pasta “docker” do projeto:
docker-compose down
Obs.: Você pode executar ambos os testes “não paralelos” e “paralelos” em um grid escalado, mas testes “não paralelos” serão executados um teste após o outro mesmo em um contexto distribuído, enquanto testes em “paralelo” irão iniciar todos ao mesmo tempo.
8. Repository
Criei uma branch nova para esse tutorial chamada “tutorial/scale-tests-docker”, clique no link abaixo para visualizar:
https://github.com/LuizGustavoR/intro-selenium-py/tree/tutorial/scale-tests-docker
Fim.
9. Bibliografia
- https://hub.docker.com/_/docker
- https://docs.docker.com/get-docker/
- https://docs.docker.com/desktop/windows/install/
- https://docs.microsoft.com/pt-br/windows/wsl/install-manual#step-4—download-the-linux-kernel-update-package
- https://github.com/SeleniumHQ/docker-selenium/blob/trunk/docker-compose-v3.yml
- https://www.programcreek.com/python/example/100023/selenium.webdriver.Remote