Source profileQuality 78/100

affaan-m/ECC/docs/es/skills/python-testing/SKILL.md

python-testing

Estrategias de pruebas Python usando pytest, metodología TDD, fixtures, mocking, parametrización y requisitos de cobertura.

Source repository stars
234,327
Declared platforms
0
Static risk flags
1
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

Estrategias completas de pruebas para aplicaciones Python usando pytest, metodología TDD y buenas prácticas.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/es/skills/python-testing"
    Safe inspection promptEditorial

    Inspect the Agent Skill "python-testing" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/es/skills/python-testing/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Fixture con Setup/Teardown

      Review the “Fixture con Setup/Teardown” section in the pinned source before continuing.

      Review and apply the “Fixture con Setup/Teardown” source section.
    2. 02

      Cuándo Activar

      Escribir código Python nuevo (seguir TDD: rojo, verde, refactorizar)

      Escribir código Python nuevo (seguir TDD: rojo, verde, refactorizar)Diseñar suites de pruebas para proyectos PythonRevisar la cobertura de pruebas Python
    3. 03

      Filosofía Central de Pruebas

      Siempre seguir el ciclo TDD:

      ROJO: Escribir una prueba que falle para el comportamiento deseadoVERDE: Escribir el código mínimo para que la prueba paseREFACTORIZAR: Mejorar el código manteniendo las pruebas en verde
    4. 04

      Desarrollo Guiado por Pruebas (TDD)

      Siempre seguir el ciclo TDD:

      ROJO: Escribir una prueba que falle para el comportamiento deseadoVERDE: Escribir el código mínimo para que la prueba paseREFACTORIZAR: Mejorar el código manteniendo las pruebas en verde
    5. 05

      Paso 1: Escribir prueba fallida (ROJO)

      def testaddnumbers(): result = add(2, 3) assert result == 5

      def testaddnumbers(): result = add(2, 3) assert result == 5

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 278

    The documentation includes network, browsing, or remote request actions.

    response = requests.get("https://api.example.com")

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score78/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/es/skills/python-testing/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Patrones de Pruebas Python

    Estrategias completas de pruebas para aplicaciones Python usando pytest, metodología TDD y buenas prácticas.

    Cuándo Activar

    • Escribir código Python nuevo (seguir TDD: rojo, verde, refactorizar)
    • Diseñar suites de pruebas para proyectos Python
    • Revisar la cobertura de pruebas Python
    • Configurar infraestructura de pruebas

    Filosofía Central de Pruebas

    Desarrollo Guiado por Pruebas (TDD)

    Siempre seguir el ciclo TDD:

    1. ROJO: Escribir una prueba que falle para el comportamiento deseado
    2. VERDE: Escribir el código mínimo para que la prueba pase
    3. REFACTORIZAR: Mejorar el código manteniendo las pruebas en verde
    # Paso 1: Escribir prueba fallida (ROJO)
    def test_add_numbers():
        result = add(2, 3)
        assert result == 5
    
    # Paso 2: Escribir implementación mínima (VERDE)
    def add(a, b):
        return a + b
    
    # Paso 3: Refactorizar si es necesario (REFACTORIZAR)
    

    Requisitos de Cobertura

    • Objetivo: 80%+ de cobertura de código
    • Rutas críticas: 100% de cobertura requerida
    • Usar pytest --cov para medir la cobertura
    pytest --cov=mypackage --cov-report=term-missing --cov-report=html
    

    Fundamentos de pytest

    Estructura Básica de Pruebas

    import pytest
    
    def test_addition():
        """Prueba la suma básica."""
        assert 2 + 2 == 4
    
    def test_string_uppercase():
        """Prueba la conversión a mayúsculas."""
        text = "hello"
        assert text.upper() == "HELLO"
    
    def test_list_append():
        """Prueba el append de lista."""
        items = [1, 2, 3]
        items.append(4)
        assert 4 in items
        assert len(items) == 4
    

    Aserciones

    # Igualdad
    assert result == expected
    
    # Desigualdad
    assert result != unexpected
    
    # Veracidad
    assert result  # Truthy
    assert not result  # Falsy
    assert result is True  # Exactamente True
    assert result is False  # Exactamente False
    assert result is None  # Exactamente None
    
    # Membresía
    assert item in collection
    assert item not in collection
    
    # Comparaciones
    assert result > 0
    assert 0 <= result <= 100
    
    # Verificación de tipo
    assert isinstance(result, str)
    
    # Prueba de excepción (enfoque preferido)
    with pytest.raises(ValueError):
        raise ValueError("mensaje de error")
    
    # Verificar mensaje de excepción
    with pytest.raises(ValueError, match="entrada inválida"):
        raise ValueError("entrada inválida proporcionada")
    

    Fixtures

    Uso Básico de Fixtures

    import pytest
    
    @pytest.fixture
    def sample_data():
        """Fixture que proporciona datos de ejemplo."""
        return {"name": "Alice", "age": 30}
    
    def test_sample_data(sample_data):
        """Prueba usando el fixture."""
        assert sample_data["name"] == "Alice"
        assert sample_data["age"] == 30
    

    Fixture con Setup/Teardown

    @pytest.fixture
    def database():
        """Fixture con setup y teardown."""
        # Setup
        db = Database(":memory:")
        db.create_tables()
        db.insert_test_data()
    
        yield db  # Proporcionar a la prueba
    
        # Teardown
        db.close()
    
    def test_database_query(database):
        """Prueba operaciones de base de datos."""
        result = database.query("SELECT * FROM users")
        assert len(result) > 0
    

    Alcances de Fixtures

    # Alcance de función (por defecto) - se ejecuta por cada prueba
    @pytest.fixture
    def temp_file():
        with open("temp.txt", "w") as f:
            yield f
        os.remove("temp.txt")
    
    # Alcance de módulo - se ejecuta una vez por módulo
    @pytest.fixture(scope="module")
    def module_db():
        db = Database(":memory:")
        db.create_tables()
        yield db
        db.close()
    
    # Alcance de sesión - se ejecuta una vez por sesión de pruebas
    @pytest.fixture(scope="session")
    def shared_resource():
        resource = ExpensiveResource()
        yield resource
        resource.cleanup()
    

    Fixture con Parámetros

    @pytest.fixture(params=[1, 2, 3])
    def number(request):
        """Fixture parametrizado."""
        return request.param
    
    def test_numbers(number):
        """La prueba se ejecuta 3 veces, una por cada parámetro."""
        assert number > 0
    

    Fixtures Autouse

    @pytest.fixture(autouse=True)
    def reset_config():
        """Se ejecuta automáticamente antes de cada prueba."""
        Config.reset()
        yield
        Config.cleanup()
    
    def test_without_fixture_call():
        # reset_config se ejecuta automáticamente
        assert Config.get_setting("debug") is False
    

    Conftest.py para Fixtures Compartidos

    # tests/conftest.py
    import pytest
    
    @pytest.fixture
    def client():
        """Fixture compartido para todas las pruebas."""
        app = create_app(testing=True)
        with app.test_client() as client:
            yield client
    
    @pytest.fixture
    def auth_headers(client):
        """Genera cabeceras de autenticación para pruebas de API."""
        response = client.post("/api/login", json={
            "username": "test",
            "password": "test"
        })
        token = response.json["token"]
        return {"Authorization": f"Bearer {token}"}
    

    Parametrización

    Parametrización Básica

    @pytest.mark.parametrize("input,expected", [
        ("hello", "HELLO"),
        ("world", "WORLD"),
        ("PyThOn", "PYTHON"),
    ])
    def test_uppercase(input, expected):
        """La prueba se ejecuta 3 veces con diferentes entradas."""
        assert input.upper() == expected
    

    Múltiples Parámetros

    @pytest.mark.parametrize("a,b,expected", [
        (2, 3, 5),
        (0, 0, 0),
        (-1, 1, 0),
        (100, 200, 300),
    ])
    def test_add(a, b, expected):
        """Prueba la suma con múltiples entradas."""
        assert add(a, b) == expected
    

    Parametrizar con IDs

    @pytest.mark.parametrize("input,expected", [
        ("valid@email.com", True),
        ("invalid", False),
        ("@no-domain.com", False),
    ], ids=["valid-email", "missing-at", "missing-domain"])
    def test_email_validation(input, expected):
        """Prueba validación de email con IDs legibles."""
        assert is_valid_email(input) is expected
    

    Markers y Selección de Pruebas

    Markers Personalizados

    # Marcar pruebas lentas
    @pytest.mark.slow
    def test_slow_operation():
        time.sleep(5)
    
    # Marcar pruebas de integración
    @pytest.mark.integration
    def test_api_integration():
        response = requests.get("https://api.example.com")
        assert response.status_code == 200
    
    # Marcar pruebas unitarias
    @pytest.mark.unit
    def test_unit_logic():
        assert calculate(2, 3) == 5
    

    Ejecutar Pruebas Específicas

    # Ejecutar solo pruebas rápidas
    pytest -m "not slow"
    
    # Ejecutar solo pruebas de integración
    pytest -m integration
    
    # Ejecutar pruebas de integración o lentas
    pytest -m "integration or slow"
    

    Configurar Markers en pytest.ini

    [pytest]
    markers =
        slow: marca pruebas como lentas
        integration: marca pruebas como de integración
        unit: marca pruebas como unitarias
    

    Mocking y Patching

    Mocking de Funciones

    from unittest.mock import patch, Mock
    
    @patch("mypackage.external_api_call")
    def test_with_mock(api_call_mock):
        """Prueba con API externa mockeada."""
        api_call_mock.return_value = {"status": "success"}
    
        result = my_function()
    
        api_call_mock.assert_called_once()
        assert result["status"] == "success"
    

    Mocking de Excepciones

    @patch("mypackage.api_call")
    def test_api_error_handling(api_call_mock):
        """Prueba manejo de errores con excepción mockeada."""
        api_call_mock.side_effect = ConnectionError("Error de red")
    
        with pytest.raises(ConnectionError):
            api_call()
    
        api_call_mock.assert_called_once()
    

    Mocking de Context Managers

    @patch("builtins.open", new_callable=mock_open)
    def test_file_reading(mock_file):
        """Prueba lectura de archivo con open mockeado."""
        mock_file.return_value.read.return_value = "contenido del archivo"
    
        result = read_file("test.txt")
    
        mock_file.assert_called_once_with("test.txt", "r")
        assert result == "contenido del archivo"
    

    Usar Autospec

    @patch("mypackage.DBConnection", autospec=True)
    def test_autospec(db_mock):
        """Prueba con autospec para detectar mal uso de API."""
        db = db_mock.return_value
        db.query("SELECT * FROM users")
    
        db_mock.assert_called_once()
    

    Mock de Propiedades

    @pytest.fixture
    def mock_config():
        """Crea un mock con una propiedad."""
        config = Mock()
        type(config).debug = PropertyMock(return_value=True)
        type(config).api_key = PropertyMock(return_value="test-key")
        return config
    

    Pruebas de Código Asíncrono

    Pruebas Async con pytest-asyncio

    import pytest
    
    @pytest.mark.asyncio
    async def test_async_function():
        """Prueba función async."""
        result = await async_add(2, 3)
        assert result == 5
    

    Fixture Async

    @pytest.fixture
    async def async_client():
        """Fixture async que proporciona cliente de prueba async."""
        app = create_app()
        async with app.test_client() as client:
            yield client
    

    Pruebas de Excepciones

    Probar Excepciones Esperadas

    def test_divide_by_zero():
        """Prueba que dividir por cero lanza ZeroDivisionError."""
        with pytest.raises(ZeroDivisionError):
            divide(10, 0)
    
    def test_custom_exception():
        """Prueba excepción personalizada con mensaje."""
        with pytest.raises(ValueError, match="entrada inválida"):
            validate_input("invalid")
    

    Pruebas con tmp_path

    def test_with_tmp_path(tmp_path):
        """Prueba usando el fixture de ruta temporal de pytest."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("hello world")
    
        result = process_file(str(test_file))
        assert result == "hello world"
        # tmp_path se limpia automáticamente
    

    Organización de Pruebas

    Estructura de Directorio

    tests/
    ├── conftest.py                 # Fixtures compartidos
    ├── __init__.py
    ├── unit/                       # Pruebas unitarias
    │   ├── __init__.py
    │   ├── test_models.py
    │   ├── test_utils.py
    │   └── test_services.py
    ├── integration/                # Pruebas de integración
    │   ├── __init__.py
    │   ├── test_api.py
    │   └── test_database.py
    └── e2e/                        # Pruebas end-to-end
        ├── __init__.py
        └── test_user_flow.py
    

    Clases de Prueba

    class TestUserService:
        """Agrupa pruebas relacionadas en una clase."""
    
        @pytest.fixture(autouse=True)
        def setup(self):
            """Setup se ejecuta antes de cada prueba en esta clase."""
            self.service = UserService()
    
        def test_create_user(self):
            """Prueba creación de usuario."""
            user = self.service.create_user("Alice")
            assert user.name == "Alice"
    
        def test_delete_user(self):
            """Prueba eliminación de usuario."""
            user = User(id=1, name="Bob")
            self.service.delete_user(user)
            assert not self.service.user_exists(1)
    

    Buenas Prácticas

    HACER

    • Seguir TDD: Escribir pruebas antes que el código (rojo-verde-refactorizar)
    • Probar una sola cosa: Cada prueba debe verificar un único comportamiento
    • Usar nombres descriptivos: test_user_login_with_invalid_credentials_fails
    • Usar fixtures: Eliminar duplicación con fixtures
    • Mockear dependencias externas: No depender de servicios externos
    • Probar casos borde: Entradas vacías, valores None, condiciones de frontera
    • Apuntar a 80%+ de cobertura: Enfocarse en rutas críticas
    • Mantener pruebas rápidas: Usar markers para separar pruebas lentas

    NO HACER

    • No probar implementación: Probar comportamiento, no internos
    • No usar condicionales complejos en pruebas: Mantener pruebas simples
    • No ignorar fallos de prueba: Todas las pruebas deben pasar
    • No probar código de terceros: Confiar en que las bibliotecas funcionan
    • No compartir estado entre pruebas: Las pruebas deben ser independientes

    Configuración de pytest

    pytest.ini

    [pytest]
    testpaths = tests
    python_files = test_*.py
    python_classes = Test*
    python_functions = test_*
    addopts =
        --strict-markers
        --disable-warnings
        --cov=mypackage
        --cov-report=term-missing
        --cov-report=html
    markers =
        slow: marca pruebas como lentas
        integration: marca pruebas como de integración
        unit: marca pruebas como unitarias
    

    Ejecutar Pruebas

    # Ejecutar todas las pruebas
    pytest
    
    # Ejecutar archivo específico
    pytest tests/test_utils.py
    
    # Ejecutar prueba específica
    pytest tests/test_utils.py::test_function
    
    # Ejecutar con salida detallada
    pytest -v
    
    # Ejecutar con cobertura
    pytest --cov=mypackage --cov-report=html
    
    # Ejecutar solo pruebas rápidas
    pytest -m "not slow"
    
    # Ejecutar hasta el primer fallo
    pytest -x
    
    # Ejecutar últimas pruebas fallidas
    pytest --lf
    
    # Ejecutar pruebas con patrón
    pytest -k "test_user"
    
    # Ejecutar con depurador al fallar
    pytest --pdb
    

    Recuerda: Las pruebas también son código. Mantenlas limpias, legibles y mantenibles. Las buenas pruebas detectan bugs; las excelentes pruebas los previenen.

    Alternatives

    Compare before choosing