Claude Code Plugins

Community-maintained marketplace

Feedback
3
0

Testing workflow patterns and quality standards. Activate when working with tests, test files, test directories, code quality tools, coverage reports, or testing tasks. Includes zero-warnings policy, targeted testing during development, mocking patterns, and best practices across languages.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name testing-workflow
description Testing workflow patterns and quality standards. Activate when working with tests, test files, test directories, code quality tools, coverage reports, or testing tasks. Includes zero-warnings policy, targeted testing during development, mocking patterns, and best practices across languages.
location user

Testing Workflow

Testing workflow patterns and quality standards for various frameworks and languages.

CRITICAL: Zero Warnings Tolerance

Treat all warnings as errors. No exceptions.

Status Output Action
✅ PASS All tests passed, no warnings Proceed
❌ FAIL Tests passed with DeprecationWarning Fix immediately
❌ FAIL Any warning present Block commit

Pre-Commit Requirements:

  • ✅ All tests pass
  • ✅ Zero warnings
  • ✅ No linting errors
  • ✅ No type errors
  • ✅ Code formatted

Never commit with:

  • ❌ Failing tests
  • ❌ Any warnings
  • ❌ Linting errors
  • ❌ Unformatted code

Testing Strategy

Test Pyramid

  1. Unit Tests (70%) - Fast, isolated, test individual functions/classes
  2. Integration Tests (20%) - Test component interactions
  3. End-to-End Tests (10%) - Full system tests

What to Test

DO test:

  • Public APIs and interfaces
  • Business logic and calculations
  • Edge cases (empty inputs, None values, boundaries)
  • Error handling and exceptions
  • Data validation
  • Critical paths through the application

DON'T test:

  • Private implementation details
  • Third-party library internals
  • Trivial getters/setters
  • Framework magic (unless you suspect bugs)

Development Workflow

During Development:

  • Run targeted tests for fast iteration
  • Fix issues immediately

Before Commit:

  • Run full suite
  • Fix all warnings/errors
  • May run 1500+ tests

Test Organization

Directory Structure

tests/
├── __init__.py / conftest.py  # Shared fixtures and setup
├── unit/                      # Fast, isolated tests
│   └── test_*.py
├── integration/               # Component interaction tests
│   └── test_*.py
└── e2e/                       # End-to-end tests
    └── test_*.py

Naming Conventions

  • Test files: test_*.py or *_test.py
  • Test classes: Test* (e.g., TestUserService)
  • Test functions: test_* (e.g., test_create_user_success)
  • Fixtures: Descriptive names (e.g., user_service, mock_database)

CRITICAL: Never name non-test classes with "Test" prefix - framework will try to collect them as tests.

Coverage Requirements

Coverage Goals

  • Minimum: 80% overall coverage
  • Critical paths: 100% coverage
  • New code: Should not decrease overall coverage
  • Focus: Behavior over line count

What to Cover

Test these:

  • Business logic, algorithms
  • Edge cases, boundary conditions
  • Error handling and exceptions
  • Integration points, APIs
  • Data validation
  • Security-critical paths

Skip these:

  • Trivial getters/setters
  • Private implementation details
  • Third-party library internals
  • Simple data classes
  • Framework magic (unless suspected bug)

Edge Cases to Test

  • Empty inputs (empty strings, empty collections)
  • None/null values
  • Boundary values (zero, maximum, minimum)
  • Single item cases
  • Negative numbers
  • Large numbers
  • Mixed positive and negative values

Test Structure - Arrange-Act-Assert Pattern

All tests follow the Arrange-Act-Assert (AAA) pattern for clarity:

  1. Arrange - Set up test data and conditions
  2. Act - Execute the functionality being tested
  3. Assert - Verify the results

This structure makes tests:

  • Easy to understand at a glance
  • Simple to maintain
  • Consistent across the codebase

Python Example

# ✅ GOOD - Clear AAA structure
def test_user_registration():
    # Arrange
    user_data = {"email": "test@example.com", "password": "secure"}
    # Act
    result = register_user(user_data)
    # Assert
    assert result.success
    assert result.user.email == "test@example.com"

# ❌ BAD - Testing implementation details
def test_internal_method():
    obj = MyClass()
    assert obj._internal_state == expected  # Don't test private state

Fixtures

# conftest.py
@pytest.fixture
def db_connection():
    conn = create_test_database()
    yield conn
    conn.close()

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

# test_file.py
def test_save_user(db_connection, sample_user):
    save_user(db_connection, sample_user)
    assert user_exists(db_connection, sample_user.email)

Scopes: function (default), class, module, session

Parametrized Tests

@pytest.mark.parametrize("input,expected", [
    ("hello", "HELLO"),
    ("world", "WORLD"),
    ("", ""),
    (None, None),
])
def test_uppercase_conversion(input, expected):
    assert to_uppercase(input) == expected

Mocking

from unittest.mock import Mock, patch

# Mock external API
@patch('module.requests.get')
def test_api_call(mock_get):
    mock_get.return_value.json.return_value = {"status": "ok"}
    result = fetch_data()
    assert result["status"] == "ok"

# Dependency injection for testability
class UserService:
    def __init__(self, db_connection):
        self.db = db_connection

def test_get_user():
    mock_db = Mock()
    mock_db.query.return_value = {"id": 1, "name": "Test"}
    service = UserService(mock_db)
    assert service.get_user(1)["name"] == "Test"

Testing Exception Handling

Tests should verify that exceptions are raised with correct messages for invalid inputs:

# ✅ GOOD - Testing exception
def test_create_user_invalid_email(user_service):
    """Test user creation fails with invalid email."""
    user_data = {
        "username": "testuser",
        "email": "invalid-email",  # Invalid format
        "age": 25
    }
    # Expect exception when invalid email is provided
    with pytest.raises(ValidationError) as exc_info:
        user_service.create_user(user_data)

    assert "email" in str(exc_info.value)

Mocking External Dependencies

Tests should mock external dependencies to:

  • Isolate the code being tested
  • Avoid real external calls (APIs, databases, network)
  • Control behavior for edge cases
  • Speed up test execution
from unittest.mock import Mock, patch

# Mock external service
@patch('module.requests.get')
def test_api_call(mock_get):
    mock_get.return_value.json.return_value = {"status": "ok"}
    result = fetch_data()
    # Verify mock was called and behavior is correct
    mock_get.assert_called_once()
    assert result["status"] == "ok"

# Dependency injection for testability
class UserService:
    def __init__(self, db_connection):
        self.db = db_connection

def test_get_user():
    mock_db = Mock()
    mock_db.query.return_value = {"id": 1, "name": "Test"}
    service = UserService(mock_db)
    assert service.get_user(1)["name"] == "Test"

Integration Testing

Integration tests verify that multiple components work together correctly. They typically:

  • Use real or test databases/services
  • Test API endpoints with real infrastructure
  • Verify component interactions
  • Run slower than unit tests
@pytest.fixture(scope="module")
def test_database():
    """Provide test database for integration tests."""
    db = create_test_database()
    run_migrations(db)
    yield db
    cleanup_database(db)

def test_user_operations(test_database):
    """Test user repository with real database."""
    user = create_user(test_database, email="test@example.com")
    assert user.id is not None

    retrieved = get_user(test_database, user.id)
    assert retrieved.email == "test@example.com"

TDD Pattern Example

# 1. Write failing test
def test_calculate_discount():
    result = calculate_discount(price=100, discount_percent=10)
    assert result == 90

# 2. Implement
def calculate_discount(price, discount_percent):
    if not 0 <= discount_percent <= 100:
        raise ValueError("Discount must be between 0 and 100")
    return price - (price * discount_percent / 100)

Test Configuration

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
    "-v",
    "--strict-markers",
    "--tb=short",
    "--cov=app",
    "--cov-report=term-missing",
]
markers = [
    "slow: marks tests as slow (deselect with '-m \"not slow\"')",
    "integration: marks tests as integration tests",
]

Test Markers and Categorization

Tests can be categorized with markers to allow selective execution:

Common marker categories:

  • slow - Tests that take longer to run (deselect with -m "not slow")
  • integration - Integration tests that use external services
  • unit - Unit tests (fast, isolated)
  • e2e - End-to-end tests
  • performance - Performance/benchmark tests
@pytest.mark.slow
def test_expensive_operation():
    result = process_large_dataset()
    assert result.success

@pytest.mark.integration
def test_database_integration():
    result = query_database()
    assert result is not None

# Run only fast tests
pytest -m "not slow"

# Run only integration tests
pytest -m integration

Performance Testing

Performance tests verify that operations complete within acceptable time limits:

import time

def test_performance_within_limit(data_processor):
    """Test processing completes within time limit."""
    large_dataset = generate_test_data(10000)

    start = time.time()
    result = data_processor.process(large_dataset)
    duration = time.time() - start

    assert duration < 1.0  # Should complete in under 1 second
    assert len(result) == 10000

Development Workflow

  1. Write/modify code
  2. Run targeted tests
  3. Fix issues immediately
  4. Run full suite (make check)
  5. Commit when zero warnings

Always:

  • ✅ Test after every change
  • ✅ Fix warnings immediately
  • ✅ Add tests for new features

Never:

  • ❌ Commit with failures/warnings
  • ❌ Skip tests after changes
  • ❌ Ignore failures as "known issues"

Essential Commands

# Development - Targeted
pytest tests/unit/test_file.py -v           # Specific file
pytest -k "test_name" -v                    # Pattern match
pytest tests/unit/test_file.py::test_func   # Exact test
pytest -v --tb=short                        # Cleaner errors

# Debugging
pytest -l                                   # Show locals
pytest --pdb                                # Debug on failure
pytest -x                                   # Stop on first failure
pytest --lf                                 # Rerun last failed

# Coverage
pytest --cov=app --cov-report=html          # HTML report
pytest --cov=app --cov-report=term-missing  # Terminal report

# Verification
make check                                  # Full suite + quality
uv run pytest                               # All tests
uv run black --check app/ tests/            # Format check
uv run isort --check app/ tests/            # Import order
uv run flake8 app/ tests/                   # Linting
uv run mypy app/ tests/                     # Type check

Test Quality Checklist

  • ✅ Run in isolation (no shared state)
  • ✅ Deterministic (same result every time)
  • ✅ Fast (mock slow operations)
  • ✅ Clear names document behavior
  • ✅ Test edge cases and errors
  • ✅ Zero warnings in output
  • ✅ >80% coverage on critical paths

TL;DR: Zero warnings policy. Follow test pyramid. Arrange-Act-Assert pattern. Mock external dependencies. Test behavior not implementation. >80% coverage on critical paths. Run targeted tests during development, full suite before commit.