This skill should be used when the user asks to "write tests", "django tests", "pytest", "test factories", "create test", "add tests", "test coverage", or mentions testing Django applications, fixtures, or factory_boy. Provides pytest-django patterns with factory_boy for test data generation.
/plugin marketplace add sergio-bershadsky/ai/plugin install django-dev@bershadsky-claude-toolsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/fixtures.mdpytest-django testing with factory_boy for fixture management.
@pytest.fixture over setUppip install pytest pytest-django factory-boy pytest-cov
pytest.ini or pyproject.toml:
# pyproject.toml
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings"
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"-ra",
"--tb=short",
]
markers = [
"slow: marks tests as slow",
"integration: marks tests as integration tests",
]
tests/
├── conftest.py # Shared fixtures
├── factories/
│ ├── __init__.py
│ ├── user.py # UserFactory
│ ├── product.py # ProductFactory
│ └── order.py # OrderFactory
├── unit/
│ ├── models/
│ │ ├── test_user.py
│ │ └── test_product.py
│ └── services/
│ └── test_user_service.py
├── integration/
│ └── api/
│ ├── test_users.py
│ └── test_products.py
└── e2e/
└── test_checkout.py
tests/conftest.py:
import pytest
from django.test import Client
from ninja.testing import TestClient
from apps.myapp.api import api
@pytest.fixture
def client():
"""Django test client."""
return Client()
@pytest.fixture
def api_client():
"""Django Ninja test client."""
return TestClient(api)
@pytest.fixture
def authenticated_client(api_client, user):
"""API client with authentication."""
api_client.headers["Authorization"] = f"Bearer {user.get_token()}"
return api_client
@pytest.fixture
def user(user_factory):
"""Default test user."""
return user_factory()
@pytest.fixture
def admin_user(user_factory):
"""Admin test user."""
return user_factory(is_staff=True, is_superuser=True)
Base factory in factories/__init__.py:
import factory
from factory.django import DjangoModelFactory
class BaseFactory(DjangoModelFactory):
"""Base factory with common patterns."""
class Meta:
abstract = True
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Override to handle soft-deleted models."""
obj = super()._create(model_class, *args, **kwargs)
return obj
User factory in factories/user.py:
import factory
from factory import fuzzy
from apps.users.models import User
from . import BaseFactory
class UserFactory(BaseFactory):
"""Factory for User model."""
class Meta:
model = User
skip_postgeneration_save = True
email = factory.LazyAttribute(
lambda obj: f"{obj.name.lower().replace(' ', '.')}@example.com"
)
name = factory.Faker("name")
is_active = True
@factory.post_generation
def password(obj, create, extracted, **kwargs):
password = extracted or "testpass123"
obj.set_password(password)
if create:
obj.save(update_fields=["password"])
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Create with explicit password handling."""
password = kwargs.pop("password", None)
user = super()._create(model_class, *args, **kwargs)
if password:
user.set_password(password)
user.save(update_fields=["password"])
return user
Order factory with relationships (factories/order.py):
import factory
from decimal import Decimal
from apps.orders.models import Order, OrderItem
from . import BaseFactory
from .user import UserFactory
from .product import ProductFactory
class OrderFactory(BaseFactory):
"""Factory for Order model."""
class Meta:
model = Order
user = factory.SubFactory(UserFactory)
status = "pending"
total = factory.LazyAttribute(lambda obj: Decimal("0.00"))
@factory.post_generation
def items(obj, create, extracted, **kwargs):
if not create:
return
if extracted:
for item in extracted:
OrderItemFactory(order=obj, **item)
else:
# Create 1-3 random items
import random
for _ in range(random.randint(1, 3)):
OrderItemFactory(order=obj)
# Update total
obj.total = sum(item.subtotal for item in obj.items.all())
obj.save(update_fields=["total"])
class OrderItemFactory(BaseFactory):
"""Factory for OrderItem model."""
class Meta:
model = OrderItem
order = factory.SubFactory(OrderFactory)
product = factory.SubFactory(ProductFactory)
quantity = factory.fuzzy.FuzzyInteger(1, 5)
unit_price = factory.LazyAttribute(lambda obj: obj.product.price)
In conftest.py:
from tests.factories.user import UserFactory
from tests.factories.product import ProductFactory
from tests.factories.order import OrderFactory
@pytest.fixture
def user_factory():
return UserFactory
@pytest.fixture
def product_factory():
return ProductFactory
@pytest.fixture
def order_factory():
return OrderFactory
# tests/unit/models/test_user.py
import pytest
from apps.users.models import User
@pytest.mark.django_db
class TestUserModel:
def test_create_user(self, user_factory):
user = user_factory(email="test@example.com", name="Test User")
assert user.email == "test@example.com"
assert user.name == "Test User"
assert user.is_active is True
assert user.id is not None
def test_soft_delete(self, user_factory):
user = user_factory()
user.delete()
assert user.is_deleted is True
assert User.objects.filter(id=user.id).exists()
def test_display_name(self, user_factory):
user = user_factory(name="John Doe")
assert user.display_name == "John Doe"
user_no_name = user_factory(name="", email="jane@example.com")
assert user_no_name.display_name == "jane"
# tests/unit/services/test_user_service.py
import pytest
from unittest.mock import patch, MagicMock
from apps.users.services import UserService
@pytest.mark.django_db
class TestUserService:
def test_create_user(self, user_factory):
user = UserService.create(
email="new@example.com",
name="New User",
password="securepass123",
)
assert user.email == "new@example.com"
assert user.check_password("securepass123")
def test_create_user_duplicate_email(self, user_factory):
user_factory(email="existing@example.com")
with pytest.raises(ValueError, match="already registered"):
UserService.create(
email="existing@example.com",
name="Another User",
password="password123",
)
@patch("apps.users.services.email.send_welcome_email")
def test_create_user_sends_email(self, mock_send, user_factory):
user = UserService.create(
email="new@example.com",
name="New User",
password="password123",
)
mock_send.assert_called_once_with(user)
# tests/integration/api/test_users.py
import pytest
@pytest.mark.django_db
class TestUsersAPI:
def test_list_users_requires_auth(self, api_client):
response = api_client.get("/users/")
assert response.status_code == 401
def test_list_users(self, authenticated_client, user_factory):
user_factory.create_batch(5)
response = authenticated_client.get("/users/")
assert response.status_code == 200
data = response.json()
assert len(data["items"]) >= 5
def test_create_user(self, authenticated_client):
response = authenticated_client.post("/users/", json={
"email": "new@example.com",
"name": "New User",
"password": "securepass123",
})
assert response.status_code == 201
assert response.json()["email"] == "new@example.com"
def test_get_user(self, authenticated_client, user_factory):
user = user_factory()
response = authenticated_client.get(f"/users/{user.id}")
assert response.status_code == 200
assert response.json()["id"] == str(user.id)
def test_get_user_not_found(self, authenticated_client):
import uuid
fake_id = uuid.uuid4()
response = authenticated_client.get(f"/users/{fake_id}")
assert response.status_code == 404
See references/fixtures.md for advanced fixture patterns including:
references/fixtures.md - Advanced fixture patterns, mocking, parametrizationThis skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.