pytest-generator

pytest-generator is a skill for Claude Code, Codex from matteocervelli/llms. It costs 28 tokens per session (3,902 once invoked), scanned A, original, MIT.

Generate pytest-based unit tests for Python code. Creates test files following pytest conventions with proper fixtures, mocking, and parametrization.

Skill for Claude CodeCodex

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add skills/matteocervelli/llms/pytest-generator
Any agent
npx skills add matteocervelli/llms --skill pytest-generator
Clone the repo
git clone --depth 1 https://github.com/matteocervelli/llms

Made for: Claude Code, Codex.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for pytest-generator

README.md
[![agentmods](https://agentmods.dev/badge/skills/matteocervelli/llms/pytest-generator.svg)](https://agentmods.dev/skills/matteocervelli/llms/pytest-generator)
Your own site
<a href="https://agentmods.dev/skills/matteocervelli/llms/pytest-generator"><img src="https://agentmods.dev/badge/skills/matteocervelli/llms/pytest-generator.svg" alt="Measured on agentmods" height="20"></a>
Per session 28 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 3,902 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00028 $0.03902
Opus 5 $0.00014 $0.01951
Sonnet 5 $0.00006 $0.00780
Haiku 4.5 $0.00003 $0.00390

Measured 2d ago against content hash a1f30fc03f69, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

pytest-generator scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

.archive/claude-v1/skills/pytest-generator/SKILL.md · 760 lines

How it starts

The opening of the file, as written. The whole thing — 760 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Pytest Generator Skill

Purpose

This skill generates pytest-based unit tests for Python code, following pytest conventions, best practices, and project standards. It creates comprehensive test suites with proper fixtures, mocking, parametrization, and coverage.

When to Use

  • Generate pytest tests for Python modules
  • Create test files for new Python features
  • Add missing test coverage to existing Python code
  • Need pytest-specific patterns (fixtures, markers, parametrize)

Test File Naming Convention

Source to Test Mapping:

  • Source: src/tools/feature/core.py
  • Test: tests/test_core.py
  • Pattern: test_<source_filename>.py

Examples:

  • src/utils/validator.pytests/test_validator.py
  • src/models/user.pytests/test_user.py
  • src/services/auth.pytests/test_auth.py

Pytest Test Generation Workflow

1. Analyze Python Source Code

Read the source file:

# Read the source to understand structure
cat src/tools/feature/core.py

Identify test targets:

  • Public functions to test
  • Classes and methods
  • Error conditions
  • Edge cases
  • Dependencies (imports, external calls)

Output: List of functions/classes requiring tests


2. Generate Test File Structure

Create test file with proper naming:

"""
Unit tests for [module name].

This module tests:
- [Functionality 1]
- [Functionality 2]
- Error handling and edge cases
"""

import pytest
from unittest.mock import Mock, MagicMock, patch, call
from typing import Any, Dict, List, Optional
from pathlib import Path

# Import functions/classes to test
from src.tools.feature.core import (
    function_to_test,
    ClassToTest,
    CustomException,
)


# ============================================================================
# Fixtures
# ============================================================================

@pytest.fixture
def sample_data() -> Dict[str, Any]:
    """
    Sample data for testing.

    Returns:
        Dictionary with test data
    """
    return {
        "id": 1,
        "name": "test",
        "value": 123,
    }


@pytest.fixture
def mock_dependency() -> Mock:
    """
    Mock external dependency.

    Returns:
        Configured mock object
    """
    mock = Mock()
    mock.method.return_value = {"status": "success"}
    mock.validate.return_value = True
    return mock


@pytest.fixture
def temp_directory(tmp_path: Path) -> Path:
    """
    Temporary directory for test files.

    Args:
        tmp_path: pytest temporary directory fixture

    Returns:
        Path to test directory
    """
    test_dir = tmp_path / "test_data"
    test_dir.mkdir()
    return test_dir


# ============================================================================
# Test Classes (for testing classes)
# ============================================================================

class TestClassName:
    """Tests for ClassName."""

    def test_init_valid_params_creates_instance(self):
        """Test initialization with valid parameters."""
        # Arrange & Act
        instance = ClassToTest(param="value")

        # Assert
        assert instance.param == "value"
        assert instance.initialized is True

    def test_method_valid_input_returns_expected(self, sample_data):
        """Test method with valid input."""
        # Arrange
        instance = ClassToTest()

        # Act
        result = instance.method(sample_data)

        # Assert
        assert result["processed"] is True
        assert result["id"] == sample_data["id"]

    def test_method_invalid_input_raises_error(self):
        """Test method with invalid input raises error."""
        # Arrange
        instance = ClassToTest()
        invalid_data = None

        # Act & Assert
        with pytest.raises(ValueError, match="Invalid input"):
            instance.method(invalid_data)


# ============================================================================
# Test Functions
# ============================================================================

def test_function_valid_input_returns_expected(sample_data):
    """Test function with valid input returns expected result."""
    # Arrange
    expected = "processed"

    # Act
    result = function_to_test(sample_data)

    # Assert
    assert result == expected


def test_function_empty_input_returns_empty():
    """Test function with empty input returns empty result."""
    # Arrange
    empty_input = {}

    # Act
    result = function_to_test(empty_input)

    # Assert
    assert result == {}


def test_function_none_input_raises_error():
    """Test function with None input raises ValueError."""
    # Arrange
    invalid_input = None

    # Act & Assert
    with pytest.raises(ValueError, match="Input cannot be None"):
        function_to_test(invalid_input)


def test_function_with_mock_dependency(mock_dependency):
    """Test function with mocked external dependency."""
    # Arrange
    input_data = {"key": "value"}

    # Act
    result = function_using_dependency(input_data, mock_dependency)

    # Assert
    assert result["status"] == "success"
    mock_dependency.method.assert_called_once_with(input_data)


@patch('src.tools.feature.core.external_api_call')
def test_function_with_patched_external(mock_api):
    """Test function with patched external API call."""
    # Arrange
    mock_api.return_value = {"data": "test"}
    input_data = {"key": "value"}

    # Act
    result = function_with_api(input_data)

    # Assert
    assert result["data"] == "test"
    mock_api.assert_called_once()


# ============================================================================
# Parametrized Tests
# ============================================================================

@pytest.mark.parametrize("input_value,expected", [
    ("[email protected]", True),
    ("invalid.email", False),
    ("", False),
    (None, False),
    ("no@domain", False),
    ("@no-user.com", False),
])
def test_validation_multiple_inputs(input_value, expected):
    """Test validation with multiple input scenarios."""
    # Act
    result = validate_input(input_value)

    # Assert
    assert result == expected


@pytest.mark.parametrize("user_type,permission", [
    ("admin", "all"),
    ("moderator", "edit"),
    ("user", "read"),
    ("guest", "none"),
])
def test_permissions_by_user_type(user_type, permission):
    """Test permissions based on user type."""
    # Arrange
    user = {"type": user_type}

    # Act
    result = get_permissions(user)

    # Assert
    assert result == permission


# ============================================================================
# Async Tests
# ============================================================================

@pytest.mark.asyncio
async def test_async_function_success():
    """Test async function with successful execution."""
    # Arrange
    input_data = {"key": "value"}

    # Act
    result = await async_function(input_data)

    # Assert
    assert result.success is True
    assert result.data == input_data


@pytest.mark.asyncio
async def test_async_function_with_mock():
    """Test async function with mocked dependency."""
    # Arrange
    mock_service = Mock()
    mock_service.fetch = AsyncMock(return_value={"data": "test"})
    input_data = {"key": "value"}

    # Act
    result = await async_function_with_service(input_data, mock_service)

    # Assert
    assert result["data"] == "test"
    mock_service.fetch.assert_awaited_once()


# ============================================================================
# Exception Tests
# ============================================================================

def test_custom_exception_raised():
    """Test that custom exception is raised."""
    # Arrange
    invalid_input = "invalid"

    # Act & Assert
    with pytest.raises(CustomException):
        function_that_raises(invalid_input)


def test_exception_message_content():
    """Test exception message contains expected content."""
    # Arrange
    invalid_input = "invalid"

    # Act & Assert
    with pytest.raises(CustomException, match="Expected error message"):
        function_that_raises(invalid_input)


def test_exception_attributes():
    """Test exception has expected attributes."""
    # Arrange
    invalid_input = "invalid"

    # Act & Assert
    with pytest.raises(CustomException) as exc_info:
        function_that_raises(invalid_input)

    assert exc_info.value.code == 400
    assert "field" in exc_info.value.details


# ============================================================================
# File Operation Tests
# ============================================================================

def test_save_file(temp_directory):
    """Test file saving functionality."""
    # Arrange
    file_path = temp_directory / "test_file.txt"
    content = "test content"

    # Act
    save_file(file_path, content)

    # Assert
    assert file_path.exists()
    assert file_path.read_text() == content


def test_read_file(temp_directory):
    """Test file reading functionality."""
    # Arrange
    file_path = temp_directory / "test_file.txt"
    expected_content = "test content"
    file_path.write_text(expected_content)

    # Act
    content = read_file(file_path)

    # Assert
    assert content == expected_content


def test_file_not_found_raises_error(temp_directory):
    """Test reading non-existent file raises error."""
    # Arrange
    missing_file = temp_directory / "missing.txt"

    # Act & Assert
    with pytest.raises(FileNotFoundError):
        read_file(missing_file)


# ============================================================================
# Marker Examples
# ============================================================================

@pytest.mark.slow
def test_slow_operation():
    """Test slow operation (marked as slow)."""
    # This test can be skipped with: pytest -m "not slow"
    pass


@pytest.mark.integration
def test_integration_scenario():
    """Test integration scenario (marked as integration)."""
    # Run only integration tests: pytest -m integration
    pass


@pytest.mark.skipif(sys.version_info < (3, 9), reason="Requires Python 3.9+")
def test_python39_feature():
    """Test feature that requires Python 3.9+."""
    pass


# ============================================================================
# Fixture Scope Examples
# ============================================================================

@pytest.fixture(scope="module")
def expensive_setup():
    """
    Expensive setup that runs once per module.

    Returns:
        Setup result
    """
    # Setup runs once for entire test module
    result = perform_expensive_setup()
    yield result
    # Teardown runs once after all tests
    cleanup(result)


@pytest.fixture(scope="function")
def per_test_setup():
    """
    Setup that runs before each test function.

    Returns:
        Setup result
    """
    # Setup runs before each test
    result = setup()
    yield result
    # Teardown runs after each test
    teardown(result)

Read the full file on GitHub · 760 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 760 lines · 28 tokens per session scan A a1f30fc03f69

Subscribe to this mod's changes

pytest-generator is a skill published in the GitHub repository matteocervelli/llms (25 stars, last pushed 3mo ago), licensed MIT. It adds 28 tokens to every session and 3,902 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-09-01.

Related

Other skills, from other repositories

systematic-debugging

Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes.

obra/superpowers · 21 tokens

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation.

obra/superpowers · 37 tokens

auto-perf-optimize

Run agent-driven VS Code performance or memory investigations. Use when asked to launch Code OSS, automate a VS Code scenario, run the Chat memory smoke runner, capture renderer heap snapshots, take workflow screenshots, compare run summaries, or drive a repeatable scenario before heap-snapshot analysis.

microsoft/vscode · 62 tokens

chat-perf

Run chat perf benchmarks and memory leak checks against the local dev build or any published VS Code version. Use when investigating chat rendering regressions, validating perf-sensitive changes to chat UI, or checking for memory leaks in the chat response pipeline.

microsoft/vscode · 51 tokens

chat-pet-sprite-creation

Use when creating or changing VS Code chat pet sprite art, sprite sheets, state animations, eye treatments, Stable/Insiders variants, or pet transitions under src/vs/workbench/contrib/chat/browser/widget/media/chatPet.

microsoft/vscode · 53 tokens

cpu-profile-analysis

Analyze V8/Chrome CPU profiles (.cpuprofile) and DevTools trace files (Trace-.json). Use when: profiling performance, investigating slow functions, comparing code paths, finding bottlenecks, analyzing timeToRequest, understanding call trees from sampling profiler data, analyzing layout/paint/rendering, investigating…

microsoft/vscode · 71 tokens