Base para automação de testes utilizando a linguagem Python com as tecnologias do Selenium WebDriver e Behave e com a estrutura organizacional CMT (Controller Model Test), uma adaptação do MVC.
Para exemplificar o funcionamento da base será automatizado a tela de login do site Netflix para cobrir os seguintes cenários de teste:
- CT01 - Acessar tela de Boas Vinda
- CT02 - Acessar tela de Login
- CT03 - Senha Inválida
- CT04 - Usuário Inválido
- CT05 - Usuário Válido
- Instalação
- Desenvolvimento
- Cenários de Teste
- Em andamento
Projeto
git clone https://github.com/andreinaoliveira/BDD-Base-Automation.git
Dependencias
- Python 3
Módulos
Os módulos devem ser instalados no cmd com os comandos abaixos
pip install behave
pip install selenium
pip install webdriver-manager
Importa a biblioteca de loggin e formata a mensagem de log. Nesse arquivo é criado as funções debug(), info() e error().
Cada função recebe a mensagem que será enviada como log. Essas funções são chamadas em controller/webdriver.
A linha referente a basic config está por padrão comentada para evitar poluição visual no terminal.
Contudo, quando houver erros, os logs serão apresentados.
import logging
log_format = '%(asctime)s :: %(name)s :: %(levelname)s :: %(module)s :: %(message)s'
#logging.basicConfig(format=log_format, level=logging.INFO, filemode='w')
def degub(message):
logging.debug(message)
def info(message):
logging.info(message)
def error(message):
logging.error(message)Em webdriver.py é criada a classe Element com os seguintes atribuitos e importações:
- driver: recebe o webdriver que será criado apenas no teste.
- name: nome do elemento ex.: Botão Sign In. O nome será enviado apenas nos log's.
- element: Ao ser encontrado, o elemento é salvo nesse atributo.
- as_Code_Type...: É a referência do elemento. É necessário atribuir valor a um dos itens para poder usar as funções da classe.
import os
import sys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from controller import logclass Element:
def __init__(self, driver, name):
self.driver = driver
self.name = name
self.element = None
self.as_1_ID = None
self.as_2_CLASS_NAME = None
self.as_3_NAME = None
self.as_4_TAG_NAME = None
self.as_5_LINK_TEXT = None
self.as_6_PARTIAL_LINK_TEXT = None
self.as_7_CSS_SELECTOR = None
self.as_8_XPATH = NoneAs funções da classe ao serem chamadas (find, click e set), executará as ações e retornará [True] ou [False] de acordo com o sucesso ou não da atividade. Portanto, além de executar a ação você poderá comparar o resultado, por exemplo, checar se retornou True, ou seja, checar se a ação foi executada com sucesso.
A função é chamada na função find(). Recebe um valor inteiro por parâmetro na variável code, o valor está no range de
1 a 8 e se refere ao tipo de referência do elemento (id, class etc.).
O código é o mesmo do atributo
as_Code_Type da classe.
Exemplo, instanciando a classe como as_1_ID o code da função deve ser _ code(1) para buscar por ID.
O ideal é que a função seja chamada apenas pelo find(), nunca diretamente.
def _code(self, code):
if code == 1:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, self.as_1_ID))
)
elif code == 2:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, self.as_2_CLASS_NAME))
)
elif code == 3:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.NAME, self.as_3_NAME))
)
elif code == 4:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.TAG_NAME, self.as_4_TAG_NAME))
)
elif code == 5:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.LINK_TEXT, self.as_5_LINK_TEXT))
)
elif code == 6:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.PARTIAL_LINK_TEXT, self.as_6_PARTIAL_LINK_TEXT))
)
elif code == 7:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, self.as_7_CSS_SELECTOR))
)
elif code == 8:
self.element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.XPATH, self.as_8_XPATH))
)
else:
log.error('Código informado em find() fora do range ou inválido.')
os.system("pause")
sys.exit()- A Função tenta localizar o elemento e envia um log informando essa tentativa.
- Não encontrando, imprime o log de erro e retorna Falso.
- Encontrando, imprime log informando sucesso e retorna True.
def find(self, code):
try:
log.degub('Buscando ' + self.name)
self._code(code)
except Exception as e:
log.error('Erro ao identificar ' + self.name)
return False
else:
log.info(self.name + ' Identificado(a)')
return True- Chama find() para atribuir valor ao atributo element da classe.
- Tenta clicar no elemento identificado.
- Não conseguindo, imprime o log de erro e retorna Falso
- Conseguindo, imprime log informando sucesso e retorna True
def click(self, code):
Element.find(self, code)
try:
self.element.click()
except Exception as e:
log.error('Erro ao clicar em ' + self.name)
return False
else:
log.info(self.name + ' Clicado(a)')
return True- Chama find() para atribuir valor ao atributo element da classe.
- Tenta clicar no elemento identificado.
- Não conseguindo, imprime o log de erro e retorna Falso.
- Conseguindo, imprime log informando sucesso e retorna True.
def set(self, code, info):
Element.find(self, code)
try:
self.element.send_keys(info)
except Exception as e:
log.error('Erro ao escerver ' + self.name)
return False
else:
log.info(self.name + ' Inserido(a)')
return TrueModelo armazena todas as páginas de um sistema web em aquivos .py diferentes. Cada arquivo possui uma classe que se refere a página web em questão. O ideal é que os principais elementos da página sejam instanciados nessa classe herdando da classe Element de controller/webdriver. Para exemplificar, criamos o modelo da página de login da Netflix (login.py)
Como atribuito possuir:
- driver
As funções da página são divididas em:
- Check: Checa se está na página, checa se alguma mensagem de erro é apresentada etc.
- Click: realiza o clique em qualquer elemento da página.
- Set: Insere alguma informação na página.
- Instancia o elemento passando o driver e o nome do elemento.
- Atribuir o valor da referência.
- Retorna a função find que busca a referência informada.
def check_page_welcome(self):
e = Element(self.driver, '[Welcome] Page')
e.as_2_CLASS_NAME = 'our-story-card-title'
return e.find(2)- Instancia o elemento passando o driver e o nome do elemento.
- Atribuir o valor da referência.
- Retorna a função click que tentará clicar na referência informada.
def click_signin_welcome(self):
e = Element(self.driver, '[Welcome] Sign In button')
e.as_5_LINK_TEXT = 'Sign In'
return e.click(5)- Instancia o elemento passando o driver e o nome do elemento.
- Atribuir o valor da referência.
- Retorna a função set que tentará inserir uma informação na referência informada.
def set_email(self, email_or_number):
e = Element(self.driver, '[Login] Email')
e.as_1_ID = 'id_userLoginId'
return e.set(1, email_or_number)Onde os testes de fato irão ocorrer. Após controller ser escrito suportando as instâncias da página em model chega a hora de criar os casos de teste, para isso, será utilizado Cucumber para escrever os cenários e Behave para interpretar a sintaxe do Gherkin
Dentro da pasta teste haverá arquivos .feature que representam o caso de teste. O arquivo refere-se a ferramenta Cucumber e está pronto para receber cenários de teste na sintaxe do Gherkin.
# language: pt
Funcionalidade: Tela de Login
Contexto:
Dado acesso ao Google Chrome
E acesso à Netflix
Cenário: CT02 - Acessar tela de login
Quando clicar em Login da tela de Boas Vindas
Então carregar tela de Login
E fechar navegadorDentro de Steps estará contido o real procedimento para a realização dos testes das features.
Quanto a importação, será necessário a importação do behave para interpretar comandos do gherkin além de alguns elementos do selenium para identificação do driver. Para gerar a conexão dos cenários de teste com os elementos da tela será importado de modelo a página correspondente ao teste. No caso, como será testado elementos de Login será importado a página login contida em model.
from behave import *
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from model.P01_Login import LoginApós a importação poderá ser escrito as ações referente ao passo definido na feature.
@when(u'clicar em Login da tela de Boas Vindas')
def clicar_login_welcome(context):
assert context.login.click_signin_welcome() is TrueComando para Execução dos cenários de teste
behave .\test\login.feature
Funcionalidade e Contexto
# language: pt
Funcionalidade: Tela de Login
Contexto:
Dado acesso ao Google Chrome
E acesso à NetflixObjetivo
- Acessar o site da Netflix e checar se é carregada a tela de Boas Vindas.
Código
# language: pt
Cenário: CT01 - Acessar tela de Boas Vindas
Então carregar tela de boas vindas
E fechar navegadorObjetivo
- Acessar o site da Netflix, clicar em "Sign In" e checar se é carregada a tela de Login.
Código
# language: pt
Cenário: CT02 - Acessar tela de login
Quando clicar em Login da tela de Boas Vindas
Então carregar tela de Login
E fechar navegadorObjetivo
- Dado o acesso ao site da Netflix e clicado em "Sign In" preenchendo um e-mail válido e senha inválida no site, checar se a mensagem referente a senha errada é apresentada.
Código
# language: pt
Esquema do Cenário: CT03 - Senha inválida
Quando clicar em Login da tela de Boas Vindas
E inserir e-mail válido "<email>"
Mas inserir senha inválida "<senha>"
E clicar em Login
Então apresentar erro de senha inválida
E fechar navegador
Exemplos:
# Primeiro exemplo a senha está realmente inválida
# e no segundo exemplo o usuário não existe
| email | senha |
| teste@gmail.com | Teste@1234 |
| testeGherkin@gmail.com | Teste@1234 |Objetivo
- Dado o acesso ao site da Netflix e clicado em "Sign In" preenchendo e-mail e senha com dados inexistente no site, checar se a mensagem de que o usuário não existe é apresentada.
Código
# language: pt
Esquema do Cenário: CT04 - Usuário inválido
Quando clicar em Login da tela de Boas Vindas
Mas inserir e-mail inválido "<email>"
E inserir senha inválida "<senha>"
E clicar em Login
Então apresentar erro de usuário inválido
E fechar navegador
Exemplos:
# Primeiro exemplo o usuário existe porém está com senha inválida
# e no segundo exemplo o usuário realmente não existe
| email | senha |
| teste@gmail.com | Teste@1234 |
| testeGherkin@gmail.com | Teste@1234 |Objetivo
- Dado o acesso ao site da Netflix e clicado em "Sign In" preenchendo e-mail e senha com dados existentes no site e clicando em "Sign In", checar se a tela de Perfis é carregada.
Código
# language: pt
Esquema do Cenário: CT05 - Usuário Válido
Quando clicar em Login da tela de Boas Vindas
E inserir e-mail válido "<email>"
E inserir senha válida "<senha>>"
E clicar em Login
Então realizar Login com sucesso
E fechar navegador
Exemplos:
| email | senha |
| valido@gmail.com | valido |









