Este artigo demonstra como utilizar arquivos YAML para parametrizar dados e passos de testes em automação com Appium e Python, facilitando a reutilização e manutenção dos casos de teste.
Parametrização de dados a partir de arquivos YAML
Para testes que requerem múltiplos conjuntos de dados, a parametrização via YAML é uma abordagem eficiente. Os dados podem ser definidos diretamente no código ou carregados de arquivos externos.
Dados embutidos no código
É possível definir listas de dados diretmaente no script de teste usando o decordaor parametrize do pytest.
import pytest
# Definição de dados para teste de login
@pytest.mark.parametrize("usuario, chave", [("pedro","senha123"), ("ana","pass456")])
def teste_login_usuario(self, usuario, chave):
tela_login = TelaLogin(driver=self.driver)
tela_login.autenticar(usuario, chave)
Nota: Certifique-se de que a configuração noReset esteja como False para permitir a execução contínua dos testes após o primeiro login bem-sucedido.
Leitura de dados de arquivo YAML externo
Os dados podem ser armazenados em um arquivo YAML e importados para o teste. Exemplo de arquivo credenciais.yaml:
- ["pedro", "senha123"]
- ["ana", "pass456"]
O teste então lê esses dados e os utiliza na parametrização:
import pytest
import yaml
from config.caminhos import caminho_yaml
credenciais = yaml.safe_load(open(caminho_yaml + "/credenciais.yaml", "r"))
@pytest.mark.parametrize("login, senha", credenciais)
def teste_acesso(login, senha):
campo_usuario = driver.find_element(by.ACCESSIBILITY_ID, "Insira seu usuário")
campo_usuario.send_keys(login)
campo_senha = driver.find_element(by.ID, "com.exemplo.app:id/senha")
campo_senha.send_keys(senha)
driver.implicitly_wait(10)
Definição de passos de teste em arquivo YAML
Além de dados, os próprios passos de execução do teste podem ser descritos em um arquivo YAML, permitindo uma abordaegm baseada em dados para a automação.
Exemplo de arquivo fluxo_login.yaml:
- id: com.exemplo.app:id/campo_senha
acao: digitar
valor: teste123
- id: com.exemplo.app:id/botao_login
Para executar esses passos, uma classe de execução pode ser implementada:
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.webdriver import WebDriver
import yaml
class ExecutorTeste:
def __init__(self, arquivo_passos):
with open(arquivo_passos, "r") as f:
self.passos = yaml.safe_load(f)
def executar(self, motorista: WebDriver):
for acao in self.passos:
if isinstance(acao, dict):
locator = None
if "id" in acao:
locator = motorista.find_element(AppiumBy.ID, acao["id"])
elif "xpath" in acao:
locator = motorista.find_element(AppiumBy.XPATH, acao["xpath"])
if "acao" in acao:
if acao["acao"] == "digitar" and "valor" in acao:
locator.send_keys(acao["valor"])
elif acao["acao"] == "clicar":
locator.click()
if "obter" in acao:
valor = locator.get_attribute(acao["obter"])
print(valor)
Extração de valores específicos de um arquivo YAML
Para ler valores específicos de um arquivo YAML, uma função utilitária pode ser criada:
import yaml
def ler_valor_yaml(arquivo, chave_primaria, chave_secundaria=None):
with open(arquivo, "r") as f:
dados = yaml.safe_load(f)
if chave_secundaria:
return dados[chave_primaria][chave_secundaria]
return dados[chave_primaria]
Exemplo de uso com um arquivo elementos.yaml:
elemento_login:
ACCESSIBILITY_ID: usuario_exemplo
id: com.exemplo.app:id/campo_usuario
id_elemento = ler_valor_yaml("caminho/elementos.yaml", "elemento_login", "id")
print(id_elemento) # Saída: com.exemplo.app:id/campo_usuario
Separação de passos e dados em arquivos YAML distintos
Em cenários mais complexos, os passos de teste e os dados podem residir em arquivos separados, promovendo maior modularidade.
Arquivo de passos etapas_cadastro.yaml:
- id: com.exemplo.app:id/campo_nome
acao: digitar
valor: teste_nome
- id: com.exemplo.app:id/campo_email
- id: com.exemplo.app:id/botao_confirmar
Arquivo de dados lista_emails.yaml:
- "email@teste.com"
- "outro@email.com"
Integração no teste:
import yaml
from config.caminhos import caminho_passos, caminho_dados
from automacao.executor import ExecutorTeste
passos = yaml.safe_load(open(caminho_passos + "/etapas_cadastro.yaml", "r"))
emails = yaml.safe_load(open(caminho_dados + "/lista_emails.yaml", "r"))
class TesteCadastro:
def __init__(self):
self.executor = ExecutorTeste(None) # Passos são carregados internamente
def executar_com_dados(self, email):
# Supondo que o executor tenha uma forma de injetar dados
# Aqui, o valor do email seria inserido no passo apropriado
self.executor.executar_com_valor("campo_email", email)
@pytest.mark.parametrize("email_teste", emails)
def teste_fluxo_cadastro(self, email_teste):
teste = TesteCadastro()
teste.executar_com_dados(email_teste)