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

thenvoi_testing_python-0.1.2.tar.gz (61.0 kB view details)

Uploaded Source

Built Distribution

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

thenvoi_testing_python-0.1.2-py3-none-any.whl (25.7 kB view details)

Uploaded Python 3

File details

Details for the file thenvoi_testing_python-0.1.2.tar.gz.

File metadata

  • Download URL: thenvoi_testing_python-0.1.2.tar.gz
  • Upload date:
  • Size: 61.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for thenvoi_testing_python-0.1.2.tar.gz
Algorithm Hash digest
SHA256 9d7029908e9f1f12fe9578467dedda0ba14dad7f48be66f92904e5a9145ff8d0
MD5 0d3e7b5c3345f0e5322be5c136d64f48
BLAKE2b-256 4bda1f80e5d38a53cda1b4befe091f64b39b75b65cec37d4cf61682b8a88971f

See more details on using hashes here.

Provenance

The following attestation bundles were made for thenvoi_testing_python-0.1.2.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 thenvoi_testing_python-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for thenvoi_testing_python-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9bd340d2ab9775d6fcaf1a60db434626916e3d0fe3114a8a47f38f51023dcf0e
MD5 3849c5d866cba691d033727b4ebc95b9
BLAKE2b-256 c20dec235b639439fef31933ca1e378e37012ad855c89e678d04ac56097062d0

See more details on using hashes here.

Provenance

The following attestation bundles were made for thenvoi_testing_python-0.1.2-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