Skip to content
Security
Skill

/pytest

Pytest testing patterns for Python. Trigger: When writing or refactoring pytest tests (fixtures, mocking, parametrize, markers). For Prowler-specific API/SDK testing conventions, also use prowler-test-api or prowler-test-sdk.

From plugin
prowler
15k39 skills1 MCP

Claude Code

$ npx -y skills add prowler-cloud/prowler --skill pytest --agent claude-code

SKILL.md

pytest.SKILL.md
name: pytest
description: >
  Pytest testing patterns for Python.
  Trigger: When writing or refactoring pytest tests (fixtures, mocking, parametrize, markers). For Prowler-specific API/SDK testing conventions, also use prowler-test-api or prowler-test-sdk.
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "1.1"
  scope: [root, sdk, api]
  auto_invoke: "Writing Python tests with pytest"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

Basic Test Structure

import pytest

class TestUserService:
    def test_create_user_success(self):
        user = create_user(name="John", email="john@test.com")
        assert user.name == "John"
        assert user.email == "john@test.com"

    def test_create_user_invalid_email_fails(self):
        with pytest.raises(ValueError, match="Invalid email"):
            create_user(name="John", email="invalid")

Fixtures

import pytest

@pytest.fixture
def user():
    """Create a test user."""
    return User(name="Test User", email="test@example.com")

@pytest.fixture
def authenticated_client(client, user):
    """Client with authenticated user."""
    client.force_login(user)
    return client

# Fixture with teardown
@pytest.fixture
def connection():
    conn = open_connection()
    yield conn  # Test runs here
    conn.close()  # Cleanup after test

# Prefer the built-in tmp_path fixture over hardcoded /tmp paths
def test_writes_file(tmp_path):
    path = tmp_path / "test_file.txt"
    path.write_text("test content")
    assert path.read_text() == "test content"

# Fixture scopes
@pytest.fixture(scope="module")  # Once per module
@pytest.fixture(scope="class")   # Once per class
@pytest.fixture(scope="session") # Once per test session

conftest.py

# tests/conftest.py - Shared fixtures
import pytest

@pytest.fixture
def db_session():
    session = create_session()
    yield session
    session.rollback()

@pytest.fixture
def api_client():
    return TestClient(app)

Mocking

from unittest.mock import patch, MagicMock

class TestPaymentService:
    def test_process_payment_success(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.return_value = {"id": "ch_123", "status": "succeeded"}

            result = process_payment(amount=100)

            assert result["status"] == "succeeded"
            mock_stripe.charge.assert_called_once_with(amount=100)

    def test_process_payment_failure(self):
        with patch("services.payment.stripe_client") as mock_stripe:
            mock_stripe.charge.side_effect = PaymentError("Card declined")

            with pytest.raises(PaymentError):
                process_payment(amount=100)

# MagicMock for complex objects
def test_with_mock_object():
    mock_user = MagicMock()
    mock_user.id = "user-123"
    mock_user.name = "Test User"
    mock_user.is_active = True

    result = get_user_info(mock_user)
    assert result["name"] == "Test User"

Parametrize

@pytest.mark.parametrize("input,expected", [
    ("hello", "HELLO"),
    ("world", "WORLD"),
    ("pytest", "PYTEST"),
])
def test_uppercase(input, expected):
    assert input.upper() == expected

@pytest.mark.parametrize("email,is_valid", [
    ("user@example.com", True),
    ("invalid-email", False),
    ("", False),
    ("user@.com", False),
])
def test_email_validation(email, is_valid):
    assert validate_email(email) == is_valid

Markers

# pytest.ini or pyproject.toml
[tool.pytest.ini_options]
markers = [
    "slow: marks tests as slow",
    "integration: marks integration tests",
]

# Usage
@pytest.mark.slow
def test_large_data_processing():
    ...

@pytest.mark.integration
def test_database_connection():
    ...

@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
    ...

@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_specific():
    ...

# Run specific markers
# pytest -m "not slow"
# pytest -m "integration"

Async Tests

Only `mcp_server/` has `pytest-asyncio`, configured with `asyncio_mode = "auto"` (no marker needed). The SDK and API test suites do not install it, so `@pytest.mark.asyncio` does nothing there.

# mcp_server/tests
async def test_async_function():
    result = await async_fetch_data()
    assert result is not None

Prowler Test Environment

| Plugin / file | Effect | |---------------|--------| | `pytest-xdist` | `-n auto` runs tests in parallel (used by CI) | | `pytest-randomly` | Random test order every run: tests must not depend on each other. Use `-p no:randomly` to reproduce an ordering bug | | `pytest-env` (`[tool.pytest_env]` in root `pyproject.toml`) | Sets fake `AWS_*` credentials for moto/boto3 | | `tests/conftest.py` | Autouse fixture that removes attributes tests set on `mock.MagicMock` and friends at class level | | `api/src/backend/pytest.ini` | `DJANGO_SETTINGS_MODULE = config.django.testing` for the API |

Commands

uv run pytest                          # Run all tests (from the component root: repo root, api/ or mcp_server/)
uv run pytest -v                       # Verbose output
uv run pytest -x                       # Stop on first failure
uv run pytest -k "test_user"           # Filter by name
uv run pytest -m "not slow"            # Filter by marker
uv run pytest --cov=./prowler          # With coverage
uv run pytest -n auto                  # Parallel (pytest-xdist)
uv run pytest --tb=short               # Short traceback
uv run pytest -p no:randomly           # Disable random ordering

References

For general pytest documentation, see:

  • **Official Docs**: https://docs.pytest.org/en/stable/

For Prowler SDK testing with provider-specific patterns (moto, MagicMock), see:

  • **Documentation**: [references/prowler-testing.md](references/prowler-testing.md)
Read more
@prowler-cloud
Ships withprowler

Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.

15k39 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
15.2k
Star history of prowler-cloud/prowler on GitHub, a chart by star-history.com

Other skills on prowler.

ai-sdk-5

ai-sdk-5

Vercel AI SDK patterns for the installed major (ui/package.json: `ai` 6.x, `@ai-sdk/react` 3.x). The skill name is historical;…

django-drf

django-drf

Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…

gh-aw

gh-aw

Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…

jsonapi

jsonapi

Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw10d23k
@nvidia@nvidiaInstall Skill

Questions about pytest.

Which coding agents can use pytest?
pytest installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.