Vanilton Pinheiro
Analista de Sistemas
IDE | PyCharm Community ou Professional |
Linguagem | Python 3.7+ |
Provisionar Ambiente | Docker |
Sistema Operacional | Windows Linux macOS |
O BDD é uma metodologia ágil de desenvolvimento que enfatiza a colaboração entre desenvolvedores, testadores e partes interessadas para criar software que realmente atenda às necessidades do cliente e com alta capacidade de automação.
1. Introdução ao Behavior Driven Development
Ferramenta de teste
Lento
Exigente por Automação
Limitado a um nível de teste
1. Introdução ao Behavior Driven Development
O BDD foi desenvolvido em 2003 por Dan North (jovem ao lado). Na época, ele percebeu a dificuldade de muitas equipes ao adotar o Test Driven Development (TDD) ou, em português, Desenvolvimento Orientado por Testes, criado por Kent Beck, pelo fato de os testes serem criados antes do código.
1. Introdução ao Behavior Driven Development
Dan North reescreveu o framework em Ruby - RBehave
2003 - Dan North criou um framework BDD - JBehave
Dan trabalhou com David Chelimsky, Aslak Hellesøy e outros para desenvolver RSpec e escrever o livro RSpec Book
1. Introdução ao Behavior Driven Development
1. Introdução ao Behavior Driven Development
1. Introdução ao Behavior Driven Development
1. Compreensão Compartilhada:
1. Introdução ao Behavior Driven Development
2. Colaboração Melhorada:
1. Introdução ao Behavior Driven Development
3. Testes Automatizados Significativos:
1. Introdução ao Behavior Driven Development
4. Foco no Valor:
1. Introdução ao Behavior Driven Development
1. Introdução ao Behavior Driven Development
2. Modelar as Entidades
1. Identificar os principais conceitos do domínio
3. Definir os agregados
4. Fábrica de instâncias
5. Desenhar os Repositórios
1. Introdução ao Behavior Driven Development
1.1 DDD - Case
6. Política de negócio
Linguagem Ubiqua
Iterar e Refinar
1. Introdução ao Behavior Driven Development
1.1 DDD - Benefícios
1. Introdução ao Behavior Driven Development
1.1 TDD - Case - Criando o projeto Python no PyCharm
2. Executar o Teste
1. Escrever um Teste para uma entidade
3. Implementar o código fonte
4. Rodar o Teste Novamente
1. Introdução ao Behavior Driven Development
1.1 TDD - Case
Iterar e Refinar
1. Introdução ao Behavior Driven Development
1.1 TDD - Benefícios
1. Introdução ao Behavior Driven Development
1. Introdução ao Behavior Driven Development
PO
Cliente
Designer
Você
Valor entregue
o que será feito?
Jornada
Como será feito?
Exemplos
Identificação do Valor
Por quê será feito?
2. Cenários e Especificações
Amazon.com.br é um(a)...?
2. Cenários e Especificações
2. Cenários e Especificações
2. Cenários e Especificações
Menos risco de falta de entendimento
Comunicação mais rápida e direta
Conhecimento do domínio por todos
Entendimento/clarificação de código
2. Cenários e Especificações
De forma muito resumida, linguagem ubíqua é: Todos falando a mesma língua e usando as mesmas palavras para definir as mesmas coisas.
2. Cenários e Especificações
2. Cenários e Especificações
2. Cenários e Especificações
2. Cenários e Especificações
O usuário efetua o login com usuário e senha válido e visualiza a tela com diversos campos
O estudante efetua o login com usuário e senha válido e visualiza a lista de provas marcadas para o dia
O usuário efetua o login com usuário e senha válido e visualiza a tela com diversos campos
2. Cenários e Especificações
class Tela:
def exibir(self):
print("Bem-vindo à Tela Principal!")
print("Aqui estão os diversos campos:")
print("Campo 1: [ ]")
print("Campo 2: [ ]")
print("Campo 3: [ ]")
class Sistema:
def __init__(self):
self.usuarios = [
Usuario(nome_usuario="usuario123", senha="senha123")]
def login(self, nome_usuario, senha):
for usuario in self.usuarios:
if usuario.nome_usuario == nome_usuario and usuario.senha == senha:
tela = Tela()
tela.exibir()
return True
return False
O usuário efetua o login com usuário e senha válido e visualiza a tela com diversos campos
2. Cenários e Especificações
class Estudante:
def __init__(self, nome_usuario, senha):
self.nome_usuario = nome_usuario
self.senha = senha
class Prova:
def __init__(self, disciplina, data, horario):
self.disciplina = disciplina
self.data = data
self.horario = horario
class Sistema:
def __init__(self):
self.estudantes = [
Estudante(nome_usuario="estudante123", senha="senha123")]
self.provas = [
Prova(disciplina="Matemática", data="2023-09-15", horario="09:00"),
Prova(disciplina="História", data="2023-09-15", horario="14:00"),
]
def listar_provas_do_dia(self):
....
O estudante efetua o login com usuário e senha válido e visualiza a lista de provas marcadas para o dia
2. Cenários e Especificações
O estudante efetua o login com usuário e senha válido e visualiza a lista de provas marcadas para o dia
2. Cenários e Especificações
Gherkin é uma linguagem que foi criada especialmente para descrições de comportamento, ela tem a capacidade de remover detalhes da lógica de programação e focar no comportamento que uma funcionalidade deve ter.
3. Linguagem Gherkin
3. Linguagem Gherkin
Given (Dado)
Descrição das condições do cenário
Given (Dado)
Descrição das condições do cenário
When
Then (Então)
And, But (E, Mas)
3. Linguagem Gherkin
3. Linguagem Gherkin
Given o usuário está logado
And o saldo da conta é $1000
When o usuário tenta sacar $1200
Then o sistema deve exibir uma mensagem de erro
But o saldo da conta ainda deve ser $1000
Given o usuário está logado
And a página principal é carregada
When o usuário clica no botão "Adicionar Item"
And preenche o formulário com os seguintes detalhes:
| Campo | Valor | Quantidade |
| Nome | Novo Item | 5 |
Then o novo item deve ser exibido na lista de itens
3. Linguagem Gherkin
Priorize o que é de suma importância
Separe texto de código
Descreva cenários em terceira pessoa
Utilize tabelas para exemplos e facilitar o entendimento
3. Linguagem Gherkin
3. Linguagem Gherkin
3. Linguagem Gherkin
Um dos benefícios das estórias de usuários é que elas capturam uma necessidade em uma única frase. Então você sabe que a estória do usuário requer mais informações e que você precisa conversar no momento apropriado com sua equipe.
Organizar um workshop de requisitos ou uma sessão de planejamento é uma ótima maneira de fazer com que toda a equipe tenha essas conversas.
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
Desenvolvimento de fora para dentro
Especificação por Exemplo
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4.1 Outside-In Development
2. Levantar e implementar demandas que impacte as partes interessadas
1. Antes de desenvolver é crucial falar com todas as partes interessadas, mesmo que elas não sejam o público principal do seu software.
3. Programar apenas o mínimo necessário (MVP)
4. Solicitar feedback útil
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4.1 Outside-In Development
Partes interessadas
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
2. Realize um workshop de requisitos com toda a equipe (quadro branco obrigatório!) para discutir as estórias de usuários escolhidas.
1. Escrever estórias com antecedência
3. Faça um brainstorming de uma lista de exemplos para cada estória de usuário.
4. Escolha um conjunto representativo de exemplos.
5. Traduza cada exemplo em um teste de aceitação (no formato Gherkin).
6. Guarde toda essa documentação em um local de fácil acesso.
4.2 Specification Workshops (Three Amigos)
Melhor qualidade dos requisitos
- Compartilhamento do risco
Perspectivas mais variadas
- Diferentes perfis e experiências
Níveis mais elevados de consenso
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
Maior adesão
- Senso de pertencimento
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
4. Integração de BDD no Ciclo de Desenvolvimento Ágil
5. Automação de Testes com BDD
Lento
Rápido
$$$
$
# de testes
5. Automação de Testes com BDD
5. Automação de Testes com BDD
5. Automação de Testes com BDD
5. Automação de Testes com BDD
5. Automação de Testes com BDD
# Biblioteca BDD
pip install pytest-bdd
# Biblioteca para manipular páginas web
pip install pytest-playwright
Vamos instalar as dependências:
5. Automação de Testes com BDD
1. No PyCharm procurar/instalar os seguintes plugins abaixo:
2. Reinicie sua IDE
5. Automação de Testes com BDD
Configure uma das seguinte estruturas de pastas:
features
│
├──frontend
│ │
│ └──auth
│ │
│ └──login.feature
└──backend
│
└──auth
│
└──login.feature
Organize seus arquivos de recursos nas pastas por grupos semânticos:
5. Automação de Testes com BDD
feature:
Neste pasta será incluído os arquivos *.feature utilizandos pela ferramenta para identificar as escritas de comportamento no formato Gherkin.
Por padrão, pytest-bdd usará o caminho do módulo atual como caminho base para localizar arquivos de recursos, mas esse comportamento pode ser alterado no arquivo de configuração pytest (ou seja, pytest.ini, tox.ini ou setup.cfg) declarando o novo caminho base na chave bdd_features_base_dir. O caminho é interpretado como relativo ao diretório raiz do pytest. Você também pode substituir o caminho base dos recursos por cenário, para substituir o caminho para testes específicos.
5. Automação de Testes com BDD
steps:
Neste pasta será incluído as implementações referentes aos arquivos .feature
tests
│
└──functional
│
└──test_auth.py
│
└ """Authentication tests."""
from pytest_bdd import scenario
@scenario('frontend/auth/login.feature')
def test_logging_in_frontend():
pass
@scenario('backend/auth/login.feature')
def test_logging_in_backend():
pass
5. Automação de Testes com BDD
Feature: Cliente se identificar no ecommerce
Como cliente de loja
gostaria de me autenticar
para realizar compras.
Scenario: Cliente autenticando na loja
Given o cliente possui registro na loja
Then o sistema confirma a autenticidade do cliente
5. Automação de Testes com BDD
Feature: Cliente se identificar no ecommerce
Como cliente de loja
gostaria de me autenticar
para realizar compras.
Scenario: Cliente autenticando na loja
Given o cliente possui registro na loja
Then o sistema confirma a autenticidade do cliente
5. Automação de Testes com BDD
A medida que escrevemos nossos arquivos .feature, precisamos gerar sua implementação incluída posteriormente nos steps
# Gerando todos steps
pytest-bdd generate tests/bdd
# Gerando steps e criando arquivo de steps
pytest-bdd generate features/some.feature > tests/functional/test_some.py
# Gerando apenas steps pendentes
pytest --generate-missing --feature tests/bdd/features
5. Automação de Testes com BDD
# Execução simples
pytest
# Executando e visualizando resultados no terminal
pytest --gherkin-terminal-reporter -v
5. Automação de Testes com BDD
5. Automação de Testes com BDD
from pytest_bdd import (
given,
when,
then,
scenario
)
@scenario('minha.feature', 'Minha Feature')
def test_minha_feature(foo):
assert foo2.title in foo.value
5. Automação de Testes com BDD
5. Automação de Testes com BDD
5. Automação de Testes com BDD
@pytest.fixture
def cliente():
cliente = Cliente(nome="Jão", email="jao@gmail.com")
return cliente
@given('o cliente possui registro na loja', target_fixture="cliente")
def verificar_cliente_registro_loja():
"""o cliente possui registro na loja."""
cliente = Cliente(nome="vava", email="jao@gmail.com")
return cliente
@then('o sistema confirma a autenticidade do cliente')
def verificar_cliente_criado(cliente):
assert cliente.nome is "Jão"
5. Automação de Testes com BDD
5. Automação de Testes com BDD
# Criar a rede para os serviços
docker network create backend
# Subir os serviços
docker compose up -d
# Criar o usuário adminstrador
docker compose run --rm shop-bdd python manage.py createsuperuser
5. Automação de Testes com BDD
api/v1/
api/v1/product/
api/v1/product/?search={query}
api/v1/category/
api/v1/category/?search={query}
api/v1/user/
api/v1/cart/
api/v1/cart/?search={query}
api/v1/cart/add/
api/v1/cart/delete/{pk}/
api/v1/cart/add_one/{pk}/
api/v1/cart/reduce_one/{pk}/
auth/
auth/login/
auth/login/refresh/
auth/register/
auth/change_password/{pk}/
auth/update_profile/{pk}/
auth/logout/
auth/change_image/
auth/delete_profile/{pk}/
5. Automação de Testes com BDD
1. Considere a seguinte feature da API Shop:
Autenticação, elabore um cenário .feature que realize o login no sistema
2. Utilizando Playwright API Testing vamos implementar o stes
Documentação da API: http://127.0.0.1:8000/doc/#operation/auth_login_create
Endpoint para autenticação
5. Automação de Testes com BDD
1. Considere a seguinte feature da API Shop:
Cadastrar categoria, elabore um cenário que realize esse comportamento
2. Implemente o feature utilizando Playwright API Testing
Documentação da API: http://127.0.0.1:8000/doc/#operation/api_category_create
Endpoint para criação da categoria
5. Automação de Testes com BDD
Organizando por pastas não conseguimos distinguir os cenários contidos nas features, e sim apenas executá-la por completo. Logo para realizar essa distinção utilizamos Tags
pytest -m "integration" --gherkin-terminal-reporter -v
pytest -m 'integration or successful' --gherkin-terminal-reporter -v
pytest -m 'not integration'
5. Automação de Testes com BDD
Realizando configurações para execução:
[pytest]
bdd_features_base_dir = tests/bdd/features/
pythonpath = .
5. Automação de Testes com BDD
Argumentos
5. Automação de Testes com BDD
@given(parsers.parse('o cliente "{nome:w}" possui registro na loja'))
def verificar_cliente_na_loja_por_nome(nome):
print(nome)
@given(parsers.parse("há {total:d} laranjas"), target_fixture="laranjas")
def ha_laranjas(total):
return {"total": total, "comida": 0}
Scenario: Argumento para os passos given, when, then
Given há 5 laranjas
When como 2 laranjas
And como 2 laranjas
Then deve haver 1 laranja
5. Automação de Testes com BDD
@given(parsers.parse('o cliente "{nome:w}" possui registro na loja'))
def verificar_cliente_na_loja_por_nome(nome):
print(nome)
@given(parsers.parse("há {total:d} laranjas"), target_fixture="laranjas")
def ha_laranjas(total):
return {"total": total, "comida": 0}
Feature: Exemplo com tabela
Scenario Outline: Comer laranjas com argumento tabulados
Given há <total> laranjas
When como <comer> laranjas
Then deve haver <restante> laranja
Examples:
| total | comer | restante |
| 12 | 5 | 7 |
| 50 | 10 | 40 |
Cenário outline deve estar em um feature separado de cenário isolado.
5. Automação de Testes com BDD
Feature: pokédex search
As a Pokemon trainer,
I want to search for pokemons in my pokédex,
So I can learn more about them.
Background:
Given the pokédex page
Scenario Outline: Name pokédex search
When the user searches for "<text>"
Then the "<pokemon>" information is shown
Examples: Pokemons
| text | pokemon |
| Pikachu | Pikachu |
| Charmander | Charmander |
@then(parse('the "{pokemon}" information is shown'), converters=dict(pokemon=str))
def the_pokemon_information_is_shown(pokemon_located, pokemon):
assert pokemon_located.__len__() > 0
assert pokemon in pokemon_located["nome"]
5. Automação de Testes com BDD
5. Automação de Testes com BDD
Execute pytest passando a opção abaixo:
pytest --cucumberjson=report.json
5. Automação de Testes com BDD
Allure é uma ferramenta de relatório de teste leve e flexível em vários idiomas projetada para criar relatórios de teste sofisticados e claros.
5. Automação de Testes com BDD
O Allure funciona conforme imagem abaixo:
5. Automação de Testes com BDD
Para utilizá-lo vamos seguir os seguintes passos:
5. Automação de Testes com BDD
Server e UI Allure
# docker-compose.yml
version: '3'
services:
allure:
image: "frankescobar/allure-docker-service"
environment:
CHECK_RESULTS_EVERY_SECONDS: 1
KEEP_HISTORY: 1
ports:
- "5050:5050"
volumes:
- ${PWD}/allure-results:/app/allure-results
- ${PWD}/allure-reports:/app/default-reports
allure-ui:
image: "frankescobar/allure-docker-service-ui"
environment:
ALLURE_DOCKER_PUBLIC_API_URL: "http://localhost:5050"
ALLURE_DOCKER_PUBLIC_API_URL_PREFIX: ""
ports:
- "5252:5252"
5. Automação de Testes com BDD
Instalar e Publicar resultado de teste com Allure
# Bibliotecas
pip install allure-pytest allure-pytest-bdd
# Gerando o resultado do teste
pytest -p no:allure_pytest --alluredir=allure-bdd-results
5. Automação de Testes com BDD
Publicar resultado de teste com Allure via API, pode-se utilizar o script abaixo ou algum presente neste endereço: https://github.com/fescobar/allure-docker-service/tree/master/allure-docker-api-usage
import os, requests, json, base64
# This directory is where you have all your results locally, generally named as `allure-results`
allure_results_directory = '/allure-results2'
# This url is where the Allure container is deployed. We are using localhost as example
allure_server = 'http://localhost:5050'
# Project ID according to existent projects in your Allure container -
# Check endpoint for project creation >> `[POST]/projects`
project_id = 'default'
# project_id = 'my-project-id'
# current_directory = os.path.dirname(os.path.realpath(__file__)) - Caso arquivo na raiz do projeto
current_directory = os.path.abspath(r"..")
results_directory = current_directory + allure_results_directory
print('RESULTS DIRECTORY PATH: ' + results_directory)
files = os.listdir(results_directory)
print('FILES:')
results = []
for file in files:
result = {}
file_path = results_directory + "/" + file
print(file_path)
if os.path.isfile(file_path):
try:
with open(file_path, "rb") as f:
content = f.read()
if content.strip():
b64_content = base64.b64encode(content)
result['file_name'] = file
result['content_base64'] = b64_content.decode('UTF-8')
results.append(result)
else:
print('Empty File skipped: ' + file_path)
finally :
f.close()
else:
print('Directory skipped: ' + file_path)
headers = {'Content-type': 'application/json'}
request_body = {
"results": results
}
json_request_body = json.dumps(request_body)
ssl_verification = True
print("------------------SEND-RESULTS------------------")
response = requests.post(allure_server + '/allure-docker-service/send-results?project_id=' + project_id, headers=headers, data=json_request_body, verify=ssl_verification)
print("STATUS CODE:")
print(response.status_code)
print("RESPONSE:")
json_response_body = json.loads(response.content)
json_prettier_response_body = json.dumps(json_response_body, indent=4, sort_keys=True)
print(json_prettier_response_body)
5. Automação de Testes com BDD
Acessando o resultado
http://localhost:5252/allure-docker-service-ui/projects/default/reports/latest
https://blog.onedaytesting.com.br/gherkin/
https://medium.com/@aparna.gopalakrishnan/https-medium-com-aparna-small-things-about-bdd-a08b8196733
https://en.wikipedia.org/wiki/Outside%E2%80%93in_software_development
https://cucumber.io/docs/bdd/better-gherkin/
https://caroli.org/historias-do-usuario-e-a-construcao-de-produtos-de-sucesso/
https://medium.com/@daniloflinhares/bdd-behavior-driven-development-2b1d0a8329e3
https://pt.wikipedia.org/wiki/Behavior_Driven_Development
https://cucumber.io/blog/bdd/where_should_you_use_bdd/
https://sol.sbc.org.br/index.php/sbqs/article/view/15231/15075
https://blog.onedaytesting.com.br/gherkin/
https://pytest-bdd.readthedocs.io/en/stable/
https://docs.pytest.org/en/stable/how-to/mark.html
vanilton18@gmail.com