Skip to main content

Shared Python testing utilities for Thenvoi repositories - fixtures, factories, and fakes

Project description

thenvoi-testing-python

Shared Python testing utilities for Thenvoi repositories. Provides fixtures, factories, and fakes for testing adapters, WebSocket clients, and API integrations.

Installation

Install from GitHub using uv:

# Core package
uv add "thenvoi-testing-python @ git+https://github.com/thenvoi/thenvoi-testing-python.git"

# With WebSocket testing support
uv add "thenvoi-testing-python[websocket] @ git+https://github.com/thenvoi/thenvoi-testing-python.git"

# With REST client testing support
uv add "thenvoi-testing-python[rest] @ git+https://github.com/thenvoi/thenvoi-testing-python.git"

# Full installation
uv add "thenvoi-testing-python[full] @ git+https://github.com/thenvoi/thenvoi-testing-python.git"

Quick Start

The package automatically registers pytest fixtures when installed. Just use them in your tests:

# Tests automatically have access to fixtures
async def test_adapter_sends_message(fake_agent_tools):
    adapter = MyAdapter()
    await adapter.process(message, fake_agent_tools)

    assert len(fake_agent_tools.messages_sent) == 1
    assert fake_agent_tools.messages_sent[0]["content"] == "Hello!"

def test_with_factory(factory):
    agent = factory.agent_me(id="test-123", name="TestBot")
    response = factory.response(agent)
    assert response.data.id == "test-123"

Components

Factories

Mock data factories for creating test objects that behave like Pydantic models:

from thenvoi_testing.factories import factory

# Create mock objects with OpenAPI example defaults
agent = factory.agent_me()
agent = factory.agent_me(id="custom-id", name="CustomBot")

# Create response wrappers
response = factory.response(agent)
list_response = factory.list_response([room1, room2])

# Available factory methods:
# - agent_me()        - AgentMe object
# - peer()            - Peer object
# - chat_room()       - ChatRoom object
# - chat_participant() - ChatParticipant object
# - chat_message()    - ChatMessage object
# - chat_event()      - ChatEvent object
# - user_profile()    - UserProfile object
# - owned_agent()     - OwnedAgent object
# - registered_agent() - RegisteredAgent (with credentials)
# - deleted_agent()   - DeletedAgent object

Fakes

Fake implementations for testing without mocking frameworks:

from thenvoi_testing.fakes import FakeAgentTools

# FakeAgentTools tracks all tool calls
tools = FakeAgentTools()
await tools.send_message("Hello!")
await tools.send_event("Processing", "thought")
await tools.add_participant("Alice")

# Assert on tracked calls
assert len(tools.messages_sent) == 1
assert tools.messages_sent[0]["content"] == "Hello!"
assert len(tools.events_sent) == 1
assert len(tools.participants_added) == 1

For WebSocket testing (requires websocket extra):

from thenvoi_testing.fakes import FakePhoenixServer

@pytest_asyncio.fixture
async def phoenix_server():
    server = FakePhoenixServer()
    await server.start()
    try:
        yield server
    finally:
        await server.stop()

async def test_websocket(phoenix_server):
    async with PHXChannelsClient(phoenix_server.url) as client:
        await client.subscribe_to_topic("test-topic", callback)
        await phoenix_server.simulate_server_event(
            "test-topic", "new_message", {"text": "hello"}
        )

Markers

Skip markers for conditional test execution:

from thenvoi_testing.markers import (
    skip_without_env,
    skip_without_envs,
    skip_with_condition,
    skip_in_ci,
    pytest_ignore_collect_in_ci,
)

# Skip if environment variable not set
requires_api = skip_without_env("THENVOI_API_KEY")

@requires_api
def test_api_call():
    ...

# Skip if any of multiple env vars not set
requires_multi_agent = skip_without_envs(
    ["THENVOI_API_KEY", "THENVOI_API_KEY_2"],
    reason="Both API keys required"
)

# Skip in CI environment
@skip_in_ci
def test_local_only():
    ...

# In conftest.py - skip integration folder in CI
def pytest_ignore_collect(collection_path):
    return pytest_ignore_collect_in_ci(str(collection_path), "integration")

Event Factories

Create WebSocket event objects for testing handlers:

from thenvoi_testing.factories.events import (
    make_message_event,
    make_room_added_event,
    make_participant_added_event,
)

# Create a message event with defaults
event = make_message_event()
assert event.type == "message_created"
assert event.payload.sender_type == "User"

# Create with custom values
event = make_message_event(
    room_id="room-123",
    content="Hello!",
    sender_id="user-456",
    sender_type="Agent",
)

Pagination Helpers

Utilities for integration tests against paginated APIs:

from thenvoi_testing.pagination import (
    fetch_all_pages,
    find_item_in_pages,
    item_exists_in_pages,
)

# Fetch all items from paginated endpoint
all_peers = fetch_all_pages(ctx, list_agent_peers)

# Find specific item with predicate
room = find_item_in_pages(
    ctx, list_agent_chats,
    lambda item: item.get("title") == "My Room"
)

# Check if item exists
if item_exists_in_pages(ctx, list_agent_chats, room_id):
    print("Room exists!")

Settings

Base settings class for integration tests using Pydantic Settings:

from pathlib import Path
from thenvoi_testing.settings import ThenvoiTestSettings

class TestSettings(ThenvoiTestSettings):
    _env_file_path = Path(__file__).parent / ".env.test"

settings = TestSettings()

# Check if credentials are available
if settings.has_api_key:
    client = create_client(settings.thenvoi_api_key)

if settings.has_multi_agent:
    # Both agents available for multi-agent tests
    pass

Example .env.test:

THENVOI_API_KEY=your-agent-api-key
TEST_AGENT_ID=your-agent-uuid
THENVOI_API_KEY_2=second-agent-key
TEST_AGENT_ID_2=second-agent-uuid
THENVOI_API_KEY_USER=user-api-key
THENVOI_BASE_URL=https://api.thenvoi.com
THENVOI_WS_URL=wss://api.thenvoi.com/api/v1/socket/websocket

Pytest Plugin

The package registers as a pytest plugin automatically. Available fixtures:

Fixture Description
fake_agent_tools Fresh FakeAgentTools instance
mock_websocket AsyncMock WebSocket client
factory MockDataFactory instance
mock_agent_api MagicMock of agent_api namespace
mock_human_api MagicMock of human_api namespace
mock_api_client AsyncMock with both APIs attached
api_client Real RestClient for integration tests (requires rest extra)
sample_room_message MessageCreatedPayload from a user
sample_agent_message MessageCreatedPayload from an agent

Integration Testing with api_client

The api_client fixture provides a real REST client for integration tests:

def test_integration(api_client):
    if api_client is None:
        pytest.skip("THENVOI_API_KEY not configured")

    response = api_client.agent_api.get_agent_me()
    assert response.data.id is not None

It uses ThenvoiTestSettings to load configuration from environment variables.

Development

# Clone the repository
git clone git@github.com:thenvoi/thenvoi-testing-python.git
cd thenvoi-testing-python

# Install with dev dependencies
uv sync --extra dev

# Run tests
uv run pytest tests/ -v

# Run linting
uv run ruff check .
uv run ruff format .

Branching & Releases

This repository uses a main-only branch strategy:

  • Branch: main (no dev branch)
  • Versioning: Git tags (e.g., v0.1.0, v0.2.0)
  • Workflow: Feature branch → PR → squash merge to main → tag release

To pin to a specific version:

uv add "thenvoi-testing-python @ git+https://github.com/thenvoi/thenvoi-testing-python.git@v0.1.0"

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

band_testing_python-0.1.4.tar.gz (62.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

band_testing_python-0.1.4-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file band_testing_python-0.1.4.tar.gz.

File metadata

  • Download URL: band_testing_python-0.1.4.tar.gz
  • Upload date:
  • Size: 62.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for band_testing_python-0.1.4.tar.gz
Algorithm Hash digest
SHA256 3a4e3bd3b8a37bda5d587a6290cc7d1a8c4b4ecbe7bb348716d632de314d87f7
MD5 4e92475faec7185da981a0c40be58c6d
BLAKE2b-256 532b47b6a5afca2f6c41f5c75557164654512af96b2a06f09fe50fac35e86d1d

See more details on using hashes here.

Provenance

The following attestation bundles were made for band_testing_python-0.1.4.tar.gz:

Publisher: release.yml on thenvoi/thenvoi-testing-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file band_testing_python-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for band_testing_python-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b5b45d56646fcb3fb1c7b3ca0925dc7354b93beaab11eddeb85a7b7550b0376c
MD5 131514f6b476c14734be0885c1556dc1
BLAKE2b-256 f463f53ebd26ac8ce6e4ee9e523e962955adb4dc003f4d2f70b582bd85863c79

See more details on using hashes here.

Provenance

The following attestation bundles were made for band_testing_python-0.1.4-py3-none-any.whl:

Publisher: release.yml on thenvoi/thenvoi-testing-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page