{
    "format": "skillpro/v1",
    "skill_id": "affaan-m-ecc-kiro-skills-python-testing-skill-md",
    "name": "python-testing",
    "version": "1.0.0",
    "description": "Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests.",
    "category": [
        "开发编程"
    ],
    "trigger_words": [],
    "tags": [
        "python",
        "writing",
        "testing"
    ],
    "source": "DeepseekModel",
    "source_url": "https://deepseekmodel.com/skill?id=affaan-m-ecc-kiro-skills-python-testing-skill-md",
    "exported_at": "2026-09-16T06:38:35+08:00",
    "system_prompt": "name python-testing description Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests. metadata {\"origin\":\"ECC\",\"globs\":[\"**/*.py\",\"**/*.pyi\"]} 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 True Test Discovery pytest automatically discovers tests following these conventions: Files: test_*.py or *_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 None Fixture 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 None Parametrization 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 == expected Multiple 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 == valid Parametrize with IDs @pytest.mark.parametrize( \"input,expected\" , [ ( \"hello\" , \"HELLO\" ), ( \"world\" , \"WORLD\" ), ], ids=[ \"lowercase\" , \"another_lowercase\" ] ) def test_uppercase ( input , expected ): assert input .upper() == expected Test 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 (): pass Run specific markers: pytest -m unit # Run only unit tests pytest -m \"not slow\" # Skip slow tests pytest -m \"unit or integration\" # Run unit OR integration Mocking 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-missing HTML Coverage Report pytest --cov=src --cov-report=html open htmlcov/index.html Coverage 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-branch Async 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 == 200 Test 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 # Configuration conftest.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 == expected Custom 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 ) def test_exception_message (): \"\"\"Test exception message\"\"\" with pytest.raises(ValueError, match = \"Age must be positive\" ): validate_age(- 1 ) def test_exception_details (): \"\"\"Capture and inspect exception\"\"\" with pytest.raises(ValidationError) as exc_info: validate_user(name= \"\" , age=- 1 ) assert \"name\" in exc_info.value.errors assert \"age\" in exc_info.value.errors Test Helpers # tests/helpers.py def assert_user_equal ( actual, expected ): \"\"\"Custom assertion helper\"\"\" assert actual. id == expected. id assert actual.name == expected.name assert actual.email == expected.email def create_test_user ( **kwargs ): \"\"\"Test data factory\"\"\" defaults = { \"name\" : \"Test User\" , \"email\" : \"test@example.com\" , \"age\" : 25 , } defaults.update(kwargs) return User(**defaults) Property-Based Testing Using hypothesis for property-based testing: from hypothesis import given, strategies as st @given( st.integers( ), st.integers( ) ) def test_addition_commutative ( a, b ): \"\"\"Test that addition is commutative\"\"\" assert a + b == b + a @given( st.lists( st.integers( ) ) ) def test_sort_idempotent ( lst ): \"\"\"Test that sorting twice gives same result\"\"\" sorted_once = sorted (lst) sorted_twice = sorted (sorted_once) assert sorted_once == sorted_twice Best Practices One assertion per test (when possible) Use descriptive test names - describe what's being tested Arrange-Act-Assert pattern - clear test structure Use fixtures for setup - avoid duplication Mock external dependencies - keep tests fast and isolated Test edge cases - empty inputs, None, boundaries Use parametrize - test multiple scenarios efficiently Keep tests independent - no shared state between tests Running Tests # Run all tests pytest # Run specific file pytest tests/test_user.py # Run specific test pytest tests/test_user.py::test_create_user # Run with verbose output pytest -v # Run with output capture disabled pytest -s # Run in parallel (requires pytest-xdist) pytest -n auto # Run only failed tests from last run",
    "model_config": {
        "provider": "deepseek",
        "model": "deepseek-chat",
        "temperature": 0.7,
        "max_tokens": 4096,
        "top_p": 0.9
    },
    "examples": [
        {
            "input": "请用python-testing帮我处理问题",
            "output": "好的，我是python-testing。Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests. 我会根据你的需求提供专业帮助。"
        },
        {
            "input": "介绍一下你的能力",
            "output": "我是python-testing，专注于开发编程领域。Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests."
        }
    ],
    "install_guide": {
        "coze": "在 Coze 平台创建 Bot -> 技能配置 -> 导入此 .skill 文件",
        "dify": "在 Dify 平台创建应用 -> 添加知识库 -> 导入此 .skill 配置",
        "claude": "将 system_prompt 字段内容复制到 Claude 自定义指令中",
        "custom": "将此 .skill 文件加载到你的 AI Agent 框架中，解析 system_prompt 和 model_config 即可使用"
    },
    "scripts": {
        "python": "# python-testing - Python extension\n# Add custom Python logic here\ndef process(input_data):\n    return input_data\n",
        "javascript": "// python-testing - JavaScript extension\n// Add custom JS logic here\nfunction process(inputData) {\n    return inputData;\n}\n"
    },
    "tools": {
        "mcp_servers": [],
        "api_endpoints": []
    },
    "dependencies": {
        "python": [],
        "node": []
    },
    "hooks": {
        "on_load": "echo \"Skill loaded: python-testing\"",
        "on_call": "",
        "on_error": "echo \"Skill error: please check logs\""
    }
}