Specification
- Skill ID
- affaan-m/ecc/python-testing
- Publisher
- affaan-m
- Repository
- ecc
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
How to use it
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
affaan-m/ecc/python-testingInstalls these files- SKILL.md
What this skill tells the agent
Python Testing
This skill provides comprehensive Python testing patterns using pytest as the primary testing framework.
Testing Framework
Use pytest as the testing framework for its powerful features and clean syntax.
Basic Test Structure
def test_user_creation():
"""Test that a user can be created with valid data"""
user = User(name="Alice", email="alice@example.com")
assert user.name == "Alice"
assert user.email == "alice@example.com"
assert user.is_active is TrueTest Discovery
pytest automatically discovers tests following these conventions:
- Files:
test_*.pyor*_test.py - Functions:
test_* - Classes:
Test*(without__init__) - Methods:
test_*
Fixtures
Fixtures provide reusable test setup and teardown:
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
@pytest.fixture
def db_session():
"""Provide a database session for tests"""
engine = create_engine("sqlite:///:memory:")
Session = sessionmaker(bind=engine)
session = Session()
# Setup
Base.metadata.create_all(engine)
yield session
# Teardown
session.close()
def test_user_repository(db_session):
"""Test using the db_session fixture"""
repo = UserRepository(db_session)
user = repo.create(name="Alice", email="alice@example.com")
assert user.id is not NoneFixture Scopes
@pytest.fixture(scope="function") # Default: per test
def user():
return User(name="Alice")
@pytest.fixture(scope="class") # Per test class
def database():
db = Database()
db.connect()
yield db
db.disconnect()
@pytest.fixture(scope="module") # Per module
def app():
return create_app()
@pytest.fixture(scope="session") # Once per test session
def config():
return load_config()Fixture Dependencies
@pytest.fixture
def database():
db = Database()
db.connect()
yield db
db.disconnect()
@pytest.fixture
def user_repository(database):
"""Fixture that depends on database fixture"""
return UserRepository(database)
def test_create_user(user_repository):
user = user_repository.create(name="Alice")
assert user.id is not NoneParametrization
Test multiple inputs with @pytest.mark.parametrize:
import pytest
@pytest.mark.parametrize("email,expected", [
("user@example.com", True),
("invalid-email", False),
("", False),
("user@", False),
("@example.com", False),
])
def test_email_validation(email, expected):
result = validate_email(email)
assert result == expectedMultiple Parameters
@pytest.mark.parametrize("name,age,valid", [
("Alice", 25, True),
("Bob", 17, False),
("", 25, False),
("Charlie", -1, False),
])
def test_user_validation(name, age, valid):
result = validate_user(name, age)
assert result == validParametrize with IDs
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("world", "WORLD"),
], ids=["lowercase", "another_lowercase"])
def test_uppercase(input, expected):
assert input.upper() == expectedTest Markers
Use markers for test categorization and selective execution:
import pytest
@pytest.mark.unit
def test_calculate_total():
"""Fast unit test"""
assert calculate_total([1, 2, 3]) == 6
@pytest.mark.integration
def test_database_connection():
"""Slower integration test"""
db = Database()
assert db.connect() is True
@pytest.mark.slow
def test_large_dataset():
"""Very slow test"""
process_million_records()
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
pass
@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires Python 3.10+")
def test_new_syntax():
passRun specific markers:
pytest -m unit # Run only unit tests
pytest -m "not slow" # Skip slow tests
pytest -m "unit or integration" # Run unit OR integrationMocking
Using unittest.mock
from unittest.mock import Mock, patch, MagicMock
def test_user_service_with_mock():
"""Test with mock repository"""
mock_repo = Mock()
mock_repo.find_by_id.return_value = User(id="1", name="Alice")
service = UserService(mock_repo)
user = service.get_user("1")
assert user.name == "Alice"
mock_repo.find_by_id.assert_called_once_with("1")
@patch('myapp.services.EmailService')
def test_send_notification(mock_email_service):
"""Test with patched dependency"""
service = NotificationService()
service.send("user@example.com", "Hello")
mock_email_service.send.assert_called_once()pytest-mock Plugin
def test_with_mocker(mocker):
"""Using pytest-mock plugin"""
mock_repo = mocker.Mock()
mock_repo.find_by_id.return_value = User(id="1", name="Alice")
service = UserService(mock_repo)
user = service.get_user("1")
assert user.name == "Alice"Coverage Analysis
Basic Coverage
pytest --cov=src --cov-report=term-missingHTML Coverage Report
pytest --cov=src --cov-report=html
open htmlcov/index.htmlCoverage Configuration
# pytest.ini or pyproject.toml
[tool.pytest.ini_options]
addopts = """
--cov=src
--cov-report=term-missing
--cov-report=html
--cov-fail-under=80
"""Branch Coverage
pytest --cov=src --cov-branchAsync Testing
Testing Async Functions
import pytest
@pytest.mark.asyncio
async def test_async_fetch_user():
"""Test async function"""
user = await fetch_user("1")
assert user.name == "Alice"
@pytest.fixture
async def async_client():
"""Async fixture"""
client = AsyncClient()
await client.connect()
yield client
await client.disconnect()
@pytest.mark.asyncio
async def test_with_async_fixture(async_client):
result = await async_client.get("/users/1")
assert result.status == 200Test Organization
Directory Structure
tests/
├── unit/
│ ├── test_models.py
│ ├── test_services.py
│ └── test_utils.py
├── integration/
│ ├── test_database.py
│ └── test_api.py
├── conftest.py # Shared fixtures
└── pytest.ini # Configurationconftest.py
# tests/conftest.py
import pytest
@pytest.fixture(scope="session")
def app():
"""Application fixture available to all tests"""
return create_app()
@pytest.fixture
def client(app):
"""Test client fixture"""
return app.test_client()
def pytest_configure(config):
"""Register custom markers"""
config.addinivalue_line("markers", "unit: Unit tests")
config.addinivalue_line("markers", "integration: Integration tests")
config.addinivalue_line("markers", "slow: Slow tests")Assertions
Basic Assertions
def test_assertions():
assert value == expected
assert value != other
assert value > 0
assert value in collection
assert isinstance(value, str)pytest Assertions with Better Error Messages
def test_with_context():
"""pytest provides detailed assertion introspection"""
result = calculate_total([1, 2, 3])
expected = 6
# pytest shows: assert 5 == 6
assert result == expectedCustom Assertion Messages
def test_with_message():
result = process_data(input_data)
assert result.is_valid, f"Expected valid result, got errors: {result.errors}"Approximate Comparisons
import pytest
def test_float_comparison():
result = 0.1 + 0.2
assert result == pytest.approx(0.3)
# With tolerance
assert result == pytest.approx(0.3, abs=1e-9)Exception Testing
import pytest
def test_raises_exception():
"""Test that function raises expected exception"""
with pytest.raises(ValueError):
validate_age(-1)
More from affaan-m
Use this skill in a project
Open any RiverX project, search the Skills panel for affaan-m/ecc/python-testing, and install it in one click.
