Skip to main content

testing-pytest

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

Ir a la instalación

Datos de origen

Repositorio
ROCm/rocprofiler-systems-skills
Última actividad en el origen
9 de febrero de 2026 a las 09:12
Idioma detectado de SKILL.md
inglés
Estrellas
4
Forks
0

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
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)
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub