Skip to main content

testing-pytest

Pytest testing skill with modern patterns - use for writing Python tests with fixtures, parametrization, and modular design

Aller à l'installation

Informations de source

Dépôt
ROCm/rocprofiler-systems-skills
Dernière activité de la source
9 février 2026 à 09:12
Langue détectée de SKILL.md
anglais
Étoiles
4
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
testing-pytest
description
Pytest testing skill with modern patterns - use for writing Python tests with fixtures, parametrization, and modular design
# Pytest Testing Skill Use this skill when writing Python tests with pytest framework. <IMPORTANT> Follow pytest best practices for modern, modular, and reusable test design. **Pytest is the standard.** Use pytest for all Python testing. **Tests MUST be isolated.** Each test should be independent and not rely on execution order or state from other tests. **Fixtures over setup/teardown.** Use pytest fixtures for test dependencies and resource management, not setUp/tearDown methods. **Parametrize for data-driven tests.** Use `@pytest.mark.parametrize` instead of writing multiple similar test functions. **Organize tests logically.** Mirror the source code structure in your test directory. Group related tests in classes when appropriate. **Test behavior, not implementation.** Focus on testing what the code does, not how it does it. This makes tests resilient to refactoring. </IMPORTANT> ## Pytest Basics ### Test Discovery and Naming Pytest automatically discovers tests following these conventions: ```python # File naming: test_*.py or *_test.py test_user.py # ✓ Discovered user_test.py # ✓ Discovered test_models.py # ✓ Discovered models.py # ✗ Not discovered # Function naming: test_* def test_user_creation(): # ✓ Discovered pass def test_invalid_email(): # ✓ Discovered pass def helper_function(): # ✗ Not a test (no test_ prefix) pass # Class naming: Test* (no __init__) class TestUser: # ✓ Discovered def test_creation(self): pass class TestUserValidation: # ✓ Discovered def test_email(self): pass class UserHelper: # ✗ Not a test class pass ``` ### Basic Test Structure ```python from myapp.models import User def test_user_creation(): """Test that a user can be created with valid data.""" # Arrange username = "alice" email = "alice@example.com" # Act user = User(username=username, email=email) # Assert assert user.username == "alice" assert user.email == "alice@example.com" assert user.is_active is True # Default value def test_user_invalid_email(): """Test that invalid email raises ValueError.""" with pytest.raises(ValueError, match="Invalid email"): User(username="bob", email="not-an-email") ``` ### Running Tests ```bash # Run all tests pytest # Run specific file pytest tests/test_user.py # Run specific test pytest tests/test_user.py::test_user_creation # Run tests matching pattern pytest -k "user and not invalid" # Run with verbose output pytest -v # Run with coverage pytest --cov=myapp --cov-report=html # Run and stop at first failure pytest -x # Run last failed tests pytest --lf # Run in parallel (requires pytest-xdist) pytest -n auto ``` ## Assertions ### Basic Assertions ```python import pytest def test_assertions(): """Demonstrate pytest assertion introspection.""" # Equality assert result == expected assert user.name == "Alice" # Identity assert value is None assert obj is not None # Membership assert "admin" in user.roles assert item not in processed_items # Comparison assert age >= 18 assert count < MAX_COUNT # Boolean assert user.is_active assert not user.is_deleted # Type checking assert isinstance(result, dict) assert isinstance(user, User) def test_approximate_equality(): """Test floating point with tolerance.""" import math result = math.sqrt(2) ** 2 assert result == pytest.approx(2.0, rel=1e-9) def test_assertion_messages(): """Add custom messages to assertions.""" assert user.age >= 18, f"User {user.name} is underage: {user.age}" ``` ### Exception Testing ```python import pytest def test_exception_raised(): """Test that exception is raised.""" with pytest.raises(ValueError): process_invalid_data() def test_exception_with_message(): """Test exception message matches pattern.""" with pytest.raises(ValueError, match="Invalid email format"): User(email="not-an-email") def test_exception_details(): """Test exception attributes.""" with pytest.raises(APIError) as exc_info: call_api_with_invalid_token() assert exc_info.value.status_code == 401 assert "authentication" in str(exc_info.value).lower() def test_no_exception(): """Test that no exception is raised.""" # Just call the function - if it raises, test fails result = process_valid_data() assert result is not None ``` ### Warnings Testing ```python import pytest import warnings def test_deprecated_function(): """Test that deprecated function shows warning.""" with pytest.warns(DeprecationWarning, match="deprecated"): old_function() def test_warning_details(): """Test warning details.""" with pytest.warns(UserWarning) as warning_list: trigger_warning() assert len(warning_list) == 1 assert "careful" in str(warning_list[0].message) ``` ## Fixtures ### Basic Fixtures ```python import pytest from myapp.database import Database from myapp.models import User @pytest.fixture def database(): """Provide a database connection for tests.""" db = Database(":memory:") db.create_tables() yield db # Provide to test db.close() # Cleanup after test @pytest.fixture def sample_user(): """Provide a sample user for tests.""" return User(username="alice", email="alice@example.com") def test_user_save(database, sample_user): """Test saving user to database.""" # Fixtures are automatically injected by name database.save(sample_user) retrieved = database.get_user(sample_user.id) assert retrieved.username == "alice" ``` ### Fixture Scopes ```python import pytest # Function scope (default): Run once per test function @pytest.fixture def temp_file(): """Create temp file for each test.""" file = create_temp_file() yield file file.delete() # Class scope: Run once per test class @pytest.fixture(scope="class") def database_connection(): """Create database connection for test class.""" conn = Database.connect() yield conn conn.close() # Module scope: Run once per test module @pytest.fixture(scope="module") def api_client(): """Create API client for entire module.""" client = APIClient() client.authenticate() yield client client.logout() # Session scope: Run once per test session @pytest.fixture(scope="session") def docker_container(): """Start Docker container for entire test session.""" container = start_docker_postgres() yield container container.stop() ``` ### Fixture Dependencies ```python import pytest @pytest.fixture def database(): """Provide database connection.""" db = Database(":memory:") db.create_tables() yield db db.close() @pytest.fixture def user_repository(database): """Provide user repository (depends on database fixture).""" return UserRepository(database) @pytest.fixture def sample_users(user_repository): """Create sample users (depends on user_repository).""" users = [ User(username="alice", email="alice@example.com"), User(username="bob", email="bob@example.com"), ] for user in users: user_repository.save(user) return users def test_find_user(user_repository, sample_users): """Test finding user by username.""" # Both fixtures are injected automatically user = user_repository.find_by_username("alice") assert user is not None assert user.email == "alice@example.com" ``` ### Autouse Fixtures ```python import pytest @pytest.fixture(autouse=True) def reset_state(): """Reset global state before each test (runs automatically).""" clear_cache() reset_counters() yield # Cleanup after test @pytest.fixture(autouse=True, scope="module") def setup_logging(): """Configure logging for all tests in module.""" configure_test_logging() ``` ### Factory Fixtures ```python import pytest @pytest.fixture def user_factory(database): """Fixture that returns a factory function for creating users.""" def _create_user(username: str, **kwargs): user = User(username=username, **kwargs) database.save(user) return user return _create_user def test_multiple_users(user_factory): """Test with multiple users created by factory.""" alice = user_factory("alice", email="alice@example.com") bob = user_factory("bob", email="bob@example.com", admin=True) assert alice.username == "alice" assert bob.is_admin is True ``` ## Parametrization ### Basic Parametrization ```python import pytest @pytest.mark.parametrize("input,expected", [ (2, 4), (3, 9), (4, 16), (5, 25), ]) def test_square(input, expected): """Test square function with multiple inputs.""" assert square(input) == expected @pytest.mark.parametrize("email", [ "user@example.com", "test+tag@domain.org", "name.surname@company.co.uk", ]) def test_valid_emails(email): """Test that valid emails are accepted.""" assert is_valid_email(email) is True @pytest.mark.parametrize("invalid_email", [ "not-an-email", "@example.com", "user@", "user name@example.com", ]) def test_invalid_emails(invalid_email): """Test that invalid emails are rejected.""" assert is_valid_email(invalid_email) is False ``` ### Multiple Parameters ```python import pytest @pytest.mark.parametrize("username,email,expected_valid", [ ("alice", "alice@example.com", True), ("bob", "bob@example.com", True), ("", "test@example.com", False), # Empty username ("alice", "not-an-email", False), # Invalid email ("a" * 100, "test@example.com", False), # Username too long ]) def test_user_validation(username, email, expected_valid): """Test user validation with various inputs.""" user = User(username=username, email=email) assert user.is_valid() == expected_valid ``` ### Parametrize with IDs ```python import pytest @pytest.mark.parametrize("input,expected", [ pytest.param(2, 4, id="two"), pytest.param(3, 9, id="three"), pytest.param(10, 100, id="ten"), ]) def test_square_with_ids(input, expected): """Test square with readable test IDs.""" assert square(input) == expected # Alternative: ids as list @pytest.mark.parametrize("value,result", [ (0, "zero"), (1, "one"), (5, "many"), ], ids=["zero", "one", "many"]) def test_number_name(value, result): assert get_name(value) == result ``` ### Combining Parametrize ```python import pytest @pytest.mark.parametrize("x", [1, 2]) @pytest.mark.parametrize("y", [3, 4]) def test_add(x, y): """Test all combinations: (1,3), (1,4), (2,3), (2,4).""" result = x + y assert result > 0 ``` ### Parametrizing Fixtures ```python import pytest @pytest.fixture(params=["sqlite", "postgres", "mysql"]) def database(request): """Parametrized fixture - runs tests with each database.""" db_type = request.param db = Database.create(db_type)
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub