Ir para o conteúdo

Integração com pytest

O servidor mock foi projetado para se integrar naturalmente com o pytest. Esta página cobre os padrões de fixture recomendados para testes isolados e repetíveis.

Padrão básico de fixture

Crie o app uma vez no escopo do módulo para maior eficiência, depois redefina o estado antes de cada teste:

import pytest
from fastapi.testclient import TestClient
from netbox_sdk.mock import create_mock_app


@pytest.fixture(scope="module")
def app():
    return create_mock_app()


@pytest.fixture()
def client(app):
    with TestClient(app) as c:
        c.post("/mock/reset")
        yield c

O scope="module" no app significa que o servidor mock (incluindo suas ~1100 rotas e análise do schema) é inicializado uma vez por módulo de teste. A fixture client por teste chama /mock/reset antes de ceder, dando a cada teste um armazenamento fresco e vazio.

Escrevendo testes

Com as fixtures acima, cada função de teste começa sem dados:

def test_criar_e_listar(client):
    client.post("/api/dcim/sites/", json={"name": "London", "slug": "london"})
    assert client.get("/api/dcim/sites/").json()["count"] == 1


def test_começa_vazio(client):
    # Independente de test_criar_e_listar — reset foi chamado antes deste teste
    assert client.get("/api/dcim/sites/").json()["count"] == 0

Posicionamento do conftest.py

Coloque fixtures compartilhadas em conftest.py para que estejam disponíveis em múltiplos módulos de teste:

# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from netbox_sdk.mock import create_mock_app


@pytest.fixture(scope="session")
def mock_app():
    """App mock com escopo de sessão — inicializado uma vez para toda a execução de testes."""
    return create_mock_app()


@pytest.fixture()
def mock_client(mock_app):
    """Client por teste com estado limpo."""
    with TestClient(mock_app) as c:
        c.post("/mock/reset")
        yield c

Fixtures específicas por versão

Use parametrize para executar os mesmos testes em múltiplas versões do NetBox:

@pytest.fixture(params=["4.3", "4.4", "4.5", "4.6"])
def versioned_client(request):
    app = create_mock_app(version=request.param)
    with TestClient(app) as c:
        c.post("/mock/reset")
        yield c


def test_versao_status(versioned_client):
    resp = versioned_client.get("/api/status/")
    assert resp.json()["netbox-version"].startswith("4.")

Combinando testes mock e reais

Use uma variável de ambiente para alternar entre o servidor mock e uma instância real do NetBox:

import os
import pytest
from fastapi.testclient import TestClient
from netbox_sdk.mock import create_mock_app


def obter_client_de_teste():
    """Retorna um TestClient para o mock ou um wrapper apontando para o NetBox real."""
    if os.getenv("NETBOX_LIVE_TEST"):
        import httpx
        base_url = os.environ["NETBOX_URL"]
        token = os.environ["NETBOX_TOKEN"]
        return httpx.Client(
            base_url=base_url,
            headers={"Authorization": f"Token {token}"},
        )
    app = create_mock_app()
    return TestClient(app)


@pytest.fixture()
def client():
    c = obter_client_de_teste()
    if isinstance(c, TestClient):
        with c as tc:
            tc.post("/mock/reset")
            yield tc
    else:
        yield c

Defina NETBOX_LIVE_TEST=1 com NETBOX_URL e NETBOX_TOKEN para executar contra uma instância real. Deixe-os sem definição para usar o mock.

Marcando testes

Atribua testes ao marcador de suíte correto para que o CI possa roteá-los corretamente:

import pytest

pytestmark = pytest.mark.suite_sdk


def test_mock_api(client):
    ...