framework-compliance-t…
Make a cloud account compliant with a security or industry framework using Prowler Cloud.
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.
Claude Code
$ npx -y skills add prowler-cloud/prowler --skill pytest --agent claude-code
Codex
$ npx skills add prowler-cloud/prowler --skill pytest -a codex -y
Cursor
$ npx skills add prowler-cloud/prowler --skill pytest -a cursor -y
Gemini CLI
$ npx skills add prowler-cloud/prowler --skill pytest -a gemini-cli -y
GitHub Copilot
$ npx skills add prowler-cloud/prowler --skill pytest -a github-copilot -y
OpenCode
$ npx skills add prowler-cloud/prowler --skill pytest -a opencode -y
Windsurf
$ npx skills add prowler-cloud/prowler --skill pytest -a windsurf -y
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
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")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# 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)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"@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# 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"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| 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 |
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
For general pytest documentation, see:
For Prowler SDK testing with provider-specific patterns (moto, MagicMock), see:
Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.
Make a cloud account compliant with a security or industry framework using Prowler Cloud.
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 REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…
Reviews Django migration files for PostgreSQL best practices specific to Prowler. Trigger: When creating migrations, running…
Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…
Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…
Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…
Extract and decrypt Windows DPAPI-protected secrets (Credential Manager, browser logins/cookies, Wi-Fi credentials, KeePass keys)…
Clean and finalize authorized natural-language text intended for readers by auditing suspicious invisible Unicode and rewriting…