Guide: Pytest Integration
Set up Receiver.email as a Pytest fixture for async email testing. This guide covers installation, fixtures, and example tests.
Prerequisites
bash
pip install receiverdotemail pytest pytest-asyncioCreate a Fixture
Add a shared fixture in conftest.py:
conftest.py
import os
import pytest
from receiverdotemail import ReceiverClient
@pytest.fixture
async def receiver():
"""Shared Receiver.email client fixture."""
async with ReceiverClient(
api_key=os.environ["RECEIVER_API_KEY"]
) as client:
yield client
@pytest.fixture
def project_id():
"""Project ID for email testing."""
return os.environ.get("RECEIVER_PROJECT_ID", "proj_abc123")
@pytest.fixture
def email_suffix():
"""Address suffix for the test project: any prefix + suffix is a valid inbox."""
return os.environ.get("RECEIVER_EMAIL_SUFFIX", "[email protected]")Write Tests
test_emails.py
import re
import time
import pytest
@pytest.mark.asyncio
async def test_welcome_email(receiver, project_id, email_suffix):
"""Test that signup sends a welcome email."""
test_addr = f"signup-{int(time.time())}{email_suffix}"
# Trigger your app to send a welcome email
await your_app.signup(email=test_addr, password="test123")
# Wait for the email
email = await receiver.emails.wait_for(
project_id=project_id,
recipient=test_addr,
timeout=30,
)
assert email is not None
assert "welcome" in email.subject.lower()
assert len(email.links) > 0
@pytest.mark.asyncio
async def test_password_reset(receiver, project_id, email_suffix):
"""Test password reset email contains a valid link."""
test_addr = f"reset-{int(time.time())}{email_suffix}"
await your_app.request_password_reset(test_addr)
email = await receiver.emails.wait_for(
project_id=project_id,
recipient=test_addr,
timeout=30,
)
assert email is not None
reset_link = next(
(l for l in email.links if "/reset" in l), None
)
assert reset_link is not None
@pytest.mark.asyncio
async def test_otp_code(receiver, project_id, email_suffix):
"""Test OTP email contains a 6-digit code."""
test_addr = f"otp-{int(time.time())}{email_suffix}"
await your_app.send_otp(test_addr)
email = await receiver.emails.wait_for(
project_id=project_id,
recipient=test_addr,
timeout=30,
)
assert email is not None
otp_match = re.search(r"\d{6}", email.subject)
assert otp_match is not None
assert len(otp_match.group(0)) == 6Configure Pytest
Set up pytest.ini or pyproject.toml for async support and appropriate timeouts:
pytest.ini
[pytest]
asyncio_mode = auto
timeout = 60Run Tests
bash
# Set your API key
export RECEIVER_API_KEY="recv_live_..."
# Run tests
pytest tests/test_emails.py -v
# Run with coverage
pytest tests/test_emails.py --cov=your_app -vTips
- Use
asyncio_mode = autoin pytest config so you don't need to mark every test with@pytest.mark.asyncio. - Increase timeout: Email tests involve network I/O. Set pytest timeout to at least 60 seconds.
- Unique addresses: Use timestamps in addresses to prevent test interference.
- Environment variables: Store API key and project ID as env vars, not in code.