pytest-test-data-factories
Patterns for creating reusable test data: factory functions for domain objects, builder patterns for complex objects, fixture factories, parameterized test data, test data inheritance, and type-safe test data generators. Use when creating test data repeatedly, building objects with many optional fields, or generating realistic test datasets. Use when: Writing tests that need domain objects, creating fixtures for multiple tests, generating test data with defaults, building complex objects with optional fields, or parameterizing tests with various data.
What this skill does
# Pytest Test Data Factories
## Purpose
Test data factories eliminate duplication and make tests more maintainable. Instead of recreating `Order` objects with the same fields in every test, factories provide sensible defaults and allow customization only where needed.
## Quick Start
Create simple factory functions in `conftest.py`:
```python
# tests/unit/conftest.py
import pytest
from datetime import datetime
from app.extraction.domain.entities import Order
from app.extraction.domain.value_objects import OrderId, Money, ProductTitle
@pytest.fixture
def create_test_order():
"""Factory fixture for creating test orders with defaults."""
def _create(
order_id: str = "order_123",
customer_name: str = "Test User",
total: float = 99.99,
) -> Order:
return Order(
order_id=OrderId(order_id),
created_at=datetime.now(),
customer_name=customer_name,
line_items=[create_test_line_item()],
total_price=Money.from_float(total),
)
return _create
# Usage in tests
def test_order_validation(create_test_order):
"""Use factory with defaults."""
order = create_test_order()
assert order.customer_name == "Test User"
def test_order_custom_name(create_test_order):
"""Override specific fields."""
order = create_test_order(customer_name="Jane Doe")
assert order.customer_name == "Jane Doe"
```
## Instructions
### Step 1: Create Basic Factory Fixtures
```python
# tests/unit/conftest.py
from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from typing import Optional
import pytest
from app.extraction.domain.entities import Order, LineItem
from app.extraction.domain.value_objects import OrderId, ProductId, ProductTitle, Money
@pytest.fixture
def create_test_order():
"""Factory for Order aggregate with sensible defaults."""
def _create(
order_id: str = "order_123",
customer_name: str = "Test User",
line_items: Optional[list[LineItem]] = None,
total: Optional[float] = None,
) -> Order:
if line_items is None:
line_items = [create_test_line_item()]
# Calculate total from line items if not provided
if total is None:
total = sum(
float(item.price.amount) * item.quantity
for item in line_items
)
return Order(
order_id=OrderId(order_id),
created_at=datetime.now(),
customer_name=customer_name,
line_items=line_items,
total_price=Money.from_float(total),
)
return _create
@pytest.fixture
def create_test_line_item():
"""Factory for LineItem entity with defaults."""
def _create(
product_id: str = "prod_1",
product_title: str = "Test Product",
quantity: int = 1,
price: float = 99.99,
) -> LineItem:
return LineItem(
product_id=ProductId(product_id),
product_title=ProductTitle(product_title),
quantity=quantity,
price=Money.from_float(price),
)
return _create
```
### Step 2: Use Builder Pattern for Complex Objects
```python
class OrderBuilder:
"""Builder for creating complex Order objects."""
def __init__(self):
self.order_id = "order_123"
self.customer_name = "Test User"
self.line_items: list[LineItem] = []
self.total: Optional[float] = None
def with_order_id(self, order_id: str) -> OrderBuilder:
"""Set order ID."""
self.order_id = order_id
return self
def with_customer_name(self, name: str) -> OrderBuilder:
"""Set customer name."""
self.customer_name = name
return self
def with_line_items(self, items: list[LineItem]) -> OrderBuilder:
"""Set line items."""
self.line_items = items
return self
def add_line_item(self, item: LineItem) -> OrderBuilder:
"""Add a single line item."""
self.line_items.append(item)
return self
def with_total(self, total: float) -> OrderBuilder:
"""Set total price."""
self.total = total
return self
def build(self) -> Order:
"""Build the Order object."""
if not self.line_items:
self.line_items = [
LineItem(
product_id=ProductId("prod_1"),
product_title=ProductTitle("Default Product"),
quantity=1,
price=Money.from_float(99.99),
)
]
# Auto-calculate total if not provided
if self.total is None:
self.total = sum(
float(item.price.amount) * item.quantity
for item in self.line_items
)
return Order(
order_id=OrderId(self.order_id),
created_at=datetime.now(),
customer_name=self.customer_name,
line_items=self.line_items,
total_price=Money.from_float(self.total),
)
# Usage
def test_with_builder():
"""Build complex order with fluent API."""
order = (OrderBuilder()
.with_customer_name("Jane Doe")
.add_line_item(LineItem(...))
.add_line_item(LineItem(...))
.build())
assert order.customer_name == "Jane Doe"
assert len(order.line_items) == 2
```
### Step 3: Create Fixture Factories (Fixture Factories)
```python
@pytest.fixture
def order_factory(create_test_order):
"""Fixture factory that returns the create_test_order factory."""
return create_test_order
def test_multiple_orders(order_factory):
"""Create multiple different orders easily."""
order1 = order_factory(order_id="order_1", customer_name="Alice")
order2 = order_factory(order_id="order_2", customer_name="Bob")
order3 = order_factory(order_id="order_3", customer_name="Charlie")
assert order1.order_id.value == "order_1"
assert order2.order_id.value == "order_2"
assert order3.order_id.value == "order_3"
```
### Step 4: Parametrize Tests with Factory-Generated Data
```python
import pytest
from decimal import Decimal
# Factory-generated test data
ORDER_TEST_CASES = [
("order_1", "Alice", 100.00, 1),
("order_2", "Bob", 250.50, 2),
("order_3", "Charlie", 999.99, 3),
]
@pytest.mark.parametrize(
"order_id,customer_name,total,item_count",
ORDER_TEST_CASES,
ids=["alice_order", "bob_order", "charlie_order"]
)
def test_order_creation_parametrized(
create_test_order,
order_id: str,
customer_name: str,
total: float,
item_count: int,
) -> None:
"""Test multiple orders with different data."""
order = create_test_order(
order_id=order_id,
customer_name=customer_name,
total=total,
)
assert order.order_id.value == order_id
assert order.customer_name == customer_name
assert float(order.total_price.amount) == total
```
### Step 5: Create Mock Response Templates
```python
# tests/unit/conftest.py or tests/unit/fixtures/responses.py
@pytest.fixture
def shopify_order_response() -> dict:
"""Mock Shopify API order response."""
return {
"id": "12345",
"created_at": "2024-01-01T10:00:00Z",
"customer": {"name": "John Doe"},
"line_items": [
{
"product_id": "prod_1",
"title": "Laptop",
"quantity": 2,
"price": "999.99",
}
],
"total_price": "1999.98",
}
@pytest.fixture
def kafka_message_template() -> dict:
"""Mock Kafka message format."""
return {
"order_id": "12345",
"created_at": "2024-01-01T10:00:00Z",
"customer_name": "John Doe",
"line_items": [
{
"product_id": "prod_1",
"product_title": "Laptop",
"quantity": 2,
"pRelated in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.