Parametrização de testes com YAML e Appium em Python

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)

Tags: Appium Python YAML pytest Automação de Testes

Publicado em 6-8 02:29 por Thomas