generate-test

MenadBt's avatarfrom MenadBt

Generates test files following TDD patterns with Given-When-Then structure. Use when creating tests for domain logic, API endpoints, or repositories.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 8, 2026

When & Why to Use This Skill

This Claude skill automates the generation of standardized test files using Test-Driven Development (TDD) patterns and the Given-When-Then structure. It streamlines the creation of unit and integration tests for domain logic, API endpoints, and repositories, ensuring consistent naming conventions and architectural alignment across the codebase. By leveraging predefined templates and Pytest fixtures, it helps developers maintain high code coverage and software quality with minimal manual boilerplate.

Use Cases

  • Domain Logic Testing: Automatically generate unit tests for complex business rules to ensure logic accuracy and handle edge cases using the Given-When-Then format.
  • API Endpoint Validation: Create integration tests for FastAPI or other web frameworks, including assertions for status codes, response payloads, and authentication errors.
  • Repository & Database Testing: Set up infrastructure tests using standardized fixtures to verify CRUD operations and database constraints within the repository layer.
  • TDD Workflow Acceleration: Rapidly scaffold test files before writing implementation code, following strict naming conventions like 'test_when_condition_then_outcome'.
  • Exception & Edge Case Handling: Generate specific test cases to verify that the system correctly raises and handles domain-specific exceptions and validation errors.
namegenerate-test
descriptionGenerates test files following TDD patterns with Given-When-Then structure. Use when creating tests for domain logic, API endpoints, or repositories.
allowed-toolsRead, Write, Glob, Grep

Generate Tests

Creates test files following the project's TDD conventions.

Test Naming Convention

Mandatory format:

def test_when_<condition>_then_<expected_outcome>():

Examples:

def test_when_item_already_exists_then_raise_ItemAlreadyExistsException():
def test_when_item_does_not_exist_then_create_item():
def test_when_user_not_authenticated_then_return_401():
def test_when_valid_request_then_return_created_item():

Test Structure

Use Given-When-Then structure without comments:

def test_when_item_already_exists_then_raise_ItemAlreadyExistsException(
    item_repository: IItemRepository,
):
    # Given - setup
    item_db = ItemDb(id=uuid.uuid4(), user_id=user_id, name="Test", description="Desc")
    item_repository.create(item_db)

    # When/Then - action and assertion
    with pytest.raises(ItemAlreadyExistsException):
        create_item(user_id, "Test", "Another desc", item_repository)

Test File Location

Mirror the source structure:

back/src/api/{module}/domain/create_item.py
back/tests/api/{module}/domain/test_create_item.py

back/src/api/{module}/infrastructure/repository.py
back/tests/api/{module}/infrastructure/test_{entity}_repository.py

Domain Test Template

import uuid

import pytest
from freezegun import freeze_time

from src.api.{module}.domain.{action} import {action_function}
from src.api.{module}.domain.exception import {Entity}NotFoundException, {Entity}AlreadyExistsException
from src.api.{module}.infrastructure.models import {Entity}Db
from src.api.{module}.infrastructure.repository import I{Entity}Repository

user_id = "test_user_123"


def test_when_{condition}_then_{outcome}(
    {entity}_repository: I{Entity}Repository,
):
    {entity}_db = {Entity}Db(id=uuid.uuid4(), user_id=user_id, name="Test", description="Desc")
    {entity}_repository.create({entity}_db)

    with pytest.raises({Entity}AlreadyExistsException):
        {action_function}(user_id, "Test", "Another desc", {entity}_repository)


@freeze_time("2023-01-01 00:00:00", tz_offset=0)
def test_when_{condition}_then_{outcome}(
    {entity}_repository: I{Entity}Repository,
    frozen_datetime,
):
    {entity}_db = {action_function}(user_id, "Test", "Description", {entity}_repository)

    assert {entity}_db.user_id == user_id
    assert {entity}_db.name == "Test"
    assert {entity}_db.created_at == frozen_datetime

Common Fixtures

Available in back/tests/conftest.py:

@pytest.fixture
def session():
    """Database session for tests."""

@pytest.fixture
def client(session):
    """FastAPI test client."""

@pytest.fixture
def frozen_datetime():
    """Current frozen time for freezegun tests."""

@pytest.fixture
def {entity}_repository(session) -> I{Entity}Repository:
    """Repository instance for testing."""
    return {Entity}Repository(session=session)

Testing Patterns

Exception Testing

def test_when_not_found_then_raise_NotFoundException(repository):
    with pytest.raises(EntityNotFoundException):
        get_entity(uuid.uuid4(), repository)

Datetime Testing

@freeze_time("2023-01-01 00:00:00", tz_offset=0)
def test_when_created_then_timestamps_set(repository, frozen_datetime):
    entity = create_entity("name", repository)
    assert entity.created_at == frozen_datetime
    assert entity.updated_at == frozen_datetime

Parameterized Testing

@pytest.mark.parametrize("name,expected", [
    ("valid", True),
    ("", False),
    (None, False),
])
def test_when_name_varies_then_validation_correct(name, expected):
    result = validate_name(name)
    assert result == expected

Running Tests

# All tests
cd back && task tests

# Specific module
uv run pytest tests/api/{module}/ -v

# Single file
uv run pytest tests/api/{module}/domain/test_create_{entity}.py -v

# Single test
uv run pytest tests/api/{module}/domain/test_create_{entity}.py::test_when_... -v