This skill should be used when writing or modifying Python tests. Covers pytest test execution with --reuse-db, function-style tests, factoryboy factories for models, and vcr for external API calls.
This skill should be used when writing or modifying Python tests. Covers pytest test execution with --reuse-db, function-style tests, factoryboy factories for models, and vcr for external API calls.
Test Writer
Overview
Write pytest tests for the Sleuth codebase following project-specific patterns.
Test Writing Workflow
When writing tests for sleuth/apps/<app>/<module>.py:
Find similar tests to copy
Look at sleuth/apps/<app>/tests/integration/test_<module>.py for patterns
Check other test files in same app for setup patterns
Identify required factories
Check sleuth/apps/<app>/tests/factories.py for app-specific factories
Most tests need OrganizationFactory + <Provider>IntegrationAuthenticationFactory
See sleuth/apps/organization/tests/factories.py for core factories
Copy existing test structure
Use function-style tests with @pytest.mark.asyncio for async code
Use vcr() context manager for external API calls
Follow naming: test_<function_name>_<scenario>
Run tests
uv run pytest --reuse-db sleuth/apps/<app>/tests/integration/test_<module>.py
Validate code quality
make check-types # Fix mypy/black errors
make lint-py
See references/factoryboy_patterns.md for creating new factories.
Common Test Patterns
Pattern 1: Testing API Clients with VCR
For apps that make external API calls (github, linear, jira, etc.):
deftest_api_call(vcr):
org = OrganizationFactory()
auth = ProviderIntegrationAuthenticationFactory(org=org)
with vcr():
result = api_client.fetch_data()
assert result isnotNone
Examples to copy:
sleuth/apps/github/tests/integration/test_client.py - GitHub API patterns
sleuth/apps/linear/tests/integration/test_client.py - Linear API patterns
sleuth/apps/jira/tests/integration/test_client.py - Jira API patterns
See references/vcr_patterns.md for VCR details.
Pattern 2: Testing Async Operations
For apps with async operations (trees, gardener, etc.):
from sleuth import tenant
@pytest.mark.asyncioasyncdeftest_org_scoped_operation():
org = await OrganizationFactory.acreate()
with tenant.context(org):
result = await some_org_scoped_function()
assert result isnotNone
See references/mocking_patterns.md for more details.