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(nodevbranch) - 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
Metadata
Release files for band-testing-python 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| band_testing_python-0.1.4.tar.gz | 62.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| band_testing_python-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.7 kB
Release files / band_testing_python-0.1.4.tar.gz
| Download URL | band_testing_python-0.1.4.tar.gz |
|---|---|
| Size | 62.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3a4e3bd3b8a37bda5d587a6290cc7d1a8c4b4ecbe7bb348716d632de314d87f7
|
|
BLAKE2b-256 checksum How to use checksums |
532b47b6a5afca2f6c41f5c75557164654512af96b2a06f09fe50fac35e86d1d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.
Transparency logRelease files / band_testing_python-0.1.4-py3-none-any.whl
| Download URL | band_testing_python-0.1.4-py3-none-any.whl |
|---|---|
| Size | 25.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b5b45d56646fcb3fb1c7b3ca0925dc7354b93beaab11eddeb85a7b7550b0376c
|
|
BLAKE2b-256 checksum How to use checksums |
f463f53ebd26ac8ce6e4ee9e523e962955adb4dc003f4d2f70b582bd85863c79
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.
Transparency logSecurity for band-testing-python 0.1.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for band_testing_python-0.1.4.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.