Otimização de Relatórios pytest-html: Técnicas Avançadas de Personalização

Este guia explora técnicas práticas para personalizar e aprimorar os relatórios gerados pelo pytest-html, focando na flexibilidade e na extração de informações úteis.

Configuração do Ambiente de Relatório

Todas as personalizações do relatório devem ser implementadas no arquivo conftest.py do seu projeto. As bibliotecas essenciais são:

from py.xml import html
import pytest

Gerenciamento da Seção de Informações do Ambiente

É possível adicionar ou remover itens da seção "Environment" do relatório. O exemplo abaixo demonstra a adição de um nome de projeto e a remoção de chaves como "JAVA_HOME" e "Plugins".

def pytest_configure(config):
    config._metadata["Projeto"] = "Testes do Portal do Cliente"
    config._metadata.pop("JAVA_HOME", None)
    config._metadata.pop("Plugins", None)

Customização do Resumo

A seção "Summary" pode ser estendida com informações adicionais.

@pytest.mark.optionalhook
def pytest_html_results_summary(prefix):
    prefix.append(html.p("Departamento: Engenharia de Qualidade"))
    prefix.append(html.p("Responsável: Ana Silva"))

Ajustes na Tabela de Rseultados

Adicionando uma Coluna de Descrição

Para tornar o relatório mais informativo, insira uma coluna de descrição e remova a coluna de links, que pode não ser utilizada.

@pytest.mark.optionalhook
def pytest_html_results_table_header(cells):
    cells.insert(1, html.th("Descrição"))
    cells.pop(-1)

@pytest.mark.optionalhook
def pytest_html_results_table_row(report, cells):
    cells.insert(1, html.td(report.description))
    cells.pop(-1)

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item, call):
    outcome = yield
    report = outcome.get_result()
    report.description = str(item.function.__doc__)

A propriedade report.description é preenchida com a docstring (__doc__) da função do caso de teste.

Controle de Exibição de Logs

Para reduzir a poluição visual, os logs podem ser ocultados para casos de teste que foram executados com sucesso.

@pytest.mark.optionalhook
def pytest_html_results_table_html(report, data):
    if report.passed:
        del data[:]
        data.append(html.div("Teste aprovado. Nenhum log detalhado.", class_='empty log'))

Integração de Screenshots em Falhas

Durante testes de UI, capturar uma screenshot automaticamente quando um teste falha ajuda drasticamente na depuração. A imagem é embutida diretamente no relatório HTML.

Implementação do Mecanismo

O padrão utiliza uma variável global e fixtures para compartilhar a instância do driver do navegador.

shared_storage = {}

@pytest.fixture
def store_driver():
    def _store(key, driver_instance):
        shared_storage[key] = driver_instance
    return _store

@pytest.fixture
def get_driver():
    def _get(key):
        return shared_storage.get(key)
    return _get

O hook a seguir verifica se o teste falhou e gera a imagem codificada em base64.

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    extras = getattr(report, 'extra', [])

    if report.when in ('call', 'setup'):
        if report.failed and not hasattr(report, 'wasxfail'):
            screenshot_data = _generate_screenshot_base64()
            image_html = (
                '<div><img src="data:image/png;base64,%s" '
                'alt="Falha" style="max-width:600px;" '
                'onclick="window.open(this.src)"/></div>' % screenshot_data
            )
            extras.append(pytest_html.extras.html(image_html))
    report.extra = extras
    report.description = str(item.function.__doc__)

def _generate_screenshot_base64():
    return shared_storage.get('driver').get_screenshot_as_base64()

Configurando o Driver no Teste

Utilize fixtures para injetar o driver e armazená-lo na variável compartilhada.

class TestUserFlow:
    @pytest.fixture(autouse=True)
    def setup_browser(self, store_driver):
        self.driver = webdriver.Chrome()
        store_driver('driver', self.driver)
        yield
        self.driver.quit()

    def test_login_successful(self):
        # Lógica do teste...
        pass

Extração de Estatísticas de Execução

Para integrar com sistemas de notificação (como e-mails), é útil obter os totais de execução de forma programática.

import time

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    collected = terminalreporter._numcollected
    passed = len([r for r in terminalreporter.stats.get('passed', []) if r.when != 'teardown'])
    failed = len([r for r in terminalreporter.stats.get('failed', []) if r.when != 'teardown'])
    errors = len([r for r in terminalreporter.stats.get('error', []) if r.when != 'teardown'])
    skipped = len([r for r in terminalreporter.stats.get('skipped', []) if r.when != 'teardown'])

    duration_sec = time.time() - terminalreporter._sessionstarttime
    success_rate = (passed / collected) * 100 if collected > 0 else 0

    summary_text = (
        "Resumo da Execução:\n"
        f"Total Coletado: {collected}\n"
        f"Aprovados: {passed}\n"
        f"Reprovados: {failed}\n"
        f"Erros: {errors}\n"
        f"Ignorados: {skipped}\n"
        f"Taxa de Sucesso: {success_rate:.2f}%\n"
        f"Duração Total: {duration_sec:.2f} segundos"
    )

    shared_storage['execution_summary'] = summary_text

O texto formatado fica disponível em shared_storage['execution_summary'] para ser utilizado em outros componentes, como o corpo de um e-mail.

Tags: pytest pytest-html conftest relatórios Automação

Publicado em 6-30 03:29