[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DAEQ7W5R344HT7GP4Z1C1K":3,"skill-same:01M6DAEQ7W5R344HT7GP4Z1C1K":61},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":35,"linkOnly":36,"markdownContent":37,"markdownBody":38,"frontMatter":39,"refName":41,"commitSha":42,"skillDirectory":43,"forksCount":14,"repositoryHtmlUrl":44,"repositoryHomepageUrl":6,"ownerHtmlUrl":45,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":46,"install":47,"resources":60},"01M6DAEQ7W5R344HT7GP4Z1C1K","django-tdd",null,"Django testing strategies with pytest-django, TDD methodology, factory_boy, mocking, coverage, and testing Django REST Framework APIs.","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-tdd\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34],"tdd","django tdd","django","testing","framework","methodology","REST","factory","coverage","pytest","strategies","2026-11-10 10:12:30",false,"---\nname: django-tdd\ndescription: Django testing strategies with pytest-django, TDD methodology, factory_boy, mocking, coverage, and testing Django REST Framework APIs.\norigin: ECC\n---\n\n# Django Testing with TDD\n\nTest-driven development for Django applications using pytest, factory_boy, and Django REST Framework.\n\n## When to Activate\n\n- Writing new Django applications\n- Implementing Django REST Framework APIs\n- Testing Django models, views, and serializers\n- Setting up testing infrastructure for Django projects\n\n## TDD Workflow for Django\n\n### Red-Green-Refactor Cycle\n\n```python\n# Step 1: RED - Write failing test\ndef test_user_creation():\n    user = User.objects.create_user(email='test@example.com', password='testpass123')\n    assert user.email == 'test@example.com'\n    assert user.check_password('testpass123')\n    assert not user.is_staff\n\n# Step 2: GREEN - Make test pass\n# Create User model or factory\n\n# Step 3: REFACTOR - Improve while keeping tests green\n```\n\n## Setup\n\n### pytest Configuration\n\n```ini\n# pytest.ini\n[pytest]\nDJANGO_SETTINGS_MODULE = config.settings.test\ntestpaths = tests\npython_files = test_*.py\npython_classes = Test*\npython_functions = test_*\naddopts =\n    --reuse-db\n    --nomigrations\n    --cov=apps\n    --cov-report=html\n    --cov-report=term-missing\n    --strict-markers\nmarkers =\n    slow: marks tests as slow\n    integration: marks tests as integration tests\n```\n\n### Test Settings\n\n```python\n# config\u002Fsettings\u002Ftest.py\nfrom .base import *\n\nDEBUG = True\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': ':memory:',\n    }\n}\n\n# Disable migrations for speed\nclass DisableMigrations:\n    def __contains__(self, item):\n        return True\n\n    def __getitem__(self, item):\n        return None\n\nMIGRATION_MODULES = DisableMigrations()\n\n# Faster password hashing\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.MD5PasswordHasher',\n]\n\n# Email backend\nEMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n\n# Celery always eager\nCELERY_TASK_ALWAYS_EAGER = True\nCELERY_TASK_EAGER_PROPAGATES = True\n```\n\n### conftest.py\n\n```python\n# tests\u002Fconftest.py\nimport pytest\nfrom django.utils import timezone\nfrom django.contrib.auth import get_user_model\n\nUser = get_user_model()\n\n@pytest.fixture(autouse=True)\ndef timezone_settings(settings):\n    \"\"\"Ensure consistent timezone.\"\"\"\n    settings.TIME_ZONE = 'UTC'\n\n@pytest.fixture\ndef user(db):\n    \"\"\"Create a test user.\"\"\"\n    return User.objects.create_user(\n        email='test@example.com',\n        password='testpass123',\n        username='testuser'\n    )\n\n@pytest.fixture\ndef admin_user(db):\n    \"\"\"Create an admin user.\"\"\"\n    return User.objects.create_superuser(\n        email='admin@example.com',\n        password='adminpass123',\n        username='admin'\n    )\n\n@pytest.fixture\ndef authenticated_client(client, user):\n    \"\"\"Return authenticated client.\"\"\"\n    client.force_login(user)\n    return client\n\n@pytest.fixture\ndef api_client():\n    \"\"\"Return DRF API client.\"\"\"\n    from rest_framework.test import APIClient\n    return APIClient()\n\n@pytest.fixture\ndef authenticated_api_client(api_client, user):\n    \"\"\"Return authenticated API client.\"\"\"\n    api_client.force_authenticate(user=user)\n    return api_client\n```\n\n## Factory Boy\n\n### Factory Setup\n\n```python\n# tests\u002Ffactories.py\nimport factory\nfrom factory import fuzzy\nfrom datetime import datetime, timedelta\nfrom django.contrib.auth import get_user_model\nfrom apps.products.models import Product, Category\n\nUser = get_user_model()\n\nclass UserFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for User model.\"\"\"\n\n    class Meta:\n        model = User\n\n    email = factory.Sequence(lambda n: f\"user{n}@example.com\")\n    username = factory.Sequence(lambda n: f\"user{n}\")\n    password = factory.PostGenerationMethodCall('set_password', 'testpass123')\n    first_name = factory.Faker('first_name')\n    last_name = factory.Faker('last_name')\n    is_active = True\n\nclass CategoryFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for Category model.\"\"\"\n\n    class Meta:\n        model = Category\n\n    name = factory.Faker('word')\n    slug = factory.LazyAttribute(lambda obj: obj.name.lower())\n    description = factory.Faker('text')\n\nclass ProductFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for Product model.\"\"\"\n\n    class Meta:\n        model = Product\n\n    name = factory.Faker('sentence', nb_words=3)\n    slug = factory.LazyAttribute(lambda obj: obj.name.lower().replace(' ', '-'))\n    description = factory.Faker('text')\n    price = fuzzy.FuzzyDecimal(10.00, 1000.00, 2)\n    stock = fuzzy.FuzzyInteger(0, 100)\n    is_active = True\n    category = factory.SubFactory(CategoryFactory)\n    created_by = factory.SubFactory(UserFactory)\n\n    @factory.post_generation\n    def tags(self, create, extracted, **kwargs):\n        \"\"\"Add tags to product.\"\"\"\n        if not create:\n            return\n        if extracted:\n            for tag in extracted:\n                self.tags.add(tag)\n```\n\n### Using Factories\n\n```python\n# tests\u002Ftest_models.py\nimport pytest\nfrom tests.factories import ProductFactory, UserFactory\n\ndef test_product_creation():\n    \"\"\"Test product creation using factory.\"\"\"\n    product = ProductFactory(price=100.00, stock=50)\n    assert product.price == 100.00\n    assert product.stock == 50\n    assert product.is_active is True\n\ndef test_product_with_tags():\n    \"\"\"Test product with tags.\"\"\"\n    tags = [TagFactory(name='electronics'), TagFactory(name='new')]\n    product = ProductFactory(tags=tags)\n    assert product.tags.count() == 2\n\ndef test_multiple_products():\n    \"\"\"Test creating multiple products.\"\"\"\n    products = ProductFactory.create_batch(10)\n    assert len(products) == 10\n```\n\n## Model Testing\n\n### Model Tests\n\n```python\n# tests\u002Ftest_models.py\nimport pytest\nfrom django.core.exceptions import ValidationError\nfrom tests.factories import UserFactory, ProductFactory\n\nclass TestUserModel:\n    \"\"\"Test User model.\"\"\"\n\n    def test_create_user(self, db):\n        \"\"\"Test creating a regular user.\"\"\"\n        user = UserFactory(email='test@example.com')\n        assert user.email == 'test@example.com'\n        assert user.check_password('testpass123')\n        assert not user.is_staff\n        assert not user.is_superuser\n\n    def test_create_superuser(self, db):\n        \"\"\"Test creating a superuser.\"\"\"\n        user = UserFactory(\n            email='admin@example.com',\n            is_staff=True,\n            is_superuser=True\n        )\n        assert user.is_staff\n        assert user.is_superuser\n\n    def test_user_str(self, db):\n        \"\"\"Test user string representation.\"\"\"\n        user = UserFactory(email='test@example.com')\n        assert str(user) == 'test@example.com'\n\nclass TestProductModel:\n    \"\"\"Test Product model.\"\"\"\n\n    def test_product_creation(self, db):\n        \"\"\"Test creating a product.\"\"\"\n        product = ProductFactory()\n        assert product.id is not None\n        assert product.is_active is True\n        assert product.created_at is not None\n\n    def test_product_slug_generation(self, db):\n        \"\"\"Test automatic slug generation.\"\"\"\n        product = ProductFactory(name='Test Product')\n        assert product.slug == 'test-product'\n\n    def test_product_price_validation(self, db):\n        \"\"\"Test price cannot be negative.\"\"\"\n        product = ProductFactory(price=-10)\n        with pytest.raises(ValidationError):\n            product.full_clean()\n\n    def test_product_manager_active(self, db):\n        \"\"\"Test active manager method.\"\"\"\n        ProductFactory.create_batch(5, is_active=True)\n        ProductFactory.create_batch(3, is_active=False)\n\n        active_count = Product.objects.active().count()\n        assert active_count == 5\n\n    def test_product_stock_management(self, db):\n        \"\"\"Test stock management.\"\"\"\n        product = ProductFactory(stock=10)\n        product.reduce_stock(5)\n        product.refresh_from_db()\n        assert product.stock == 5\n\n        with pytest.raises(ValueError):\n            product.reduce_stock(10)  # Not enough stock\n```\n\n## View Testing\n\n### Django View Testing\n\n```python\n# tests\u002Ftest_views.py\nimport pytest\nfrom django.urls import reverse\nfrom tests.factories import ProductFactory, UserFactory\n\nclass TestProductViews:\n    \"\"\"Test product views.\"\"\"\n\n    def test_product_list(self, client, db):\n        \"\"\"Test product list view.\"\"\"\n        ProductFactory.create_batch(10)\n\n        response = client.get(reverse('products:list'))\n\n        assert response.status_code == 200\n        assert len(response.context['products']) == 10\n\n    def test_product_detail(self, client, db):\n        \"\"\"Test product detail view.\"\"\"\n        product = ProductFactory()\n\n        response = client.get(reverse('products:detail', kwargs={'slug': product.slug}))\n\n        assert response.status_code == 200\n        assert response.context['product'] == product\n\n    def test_product_create_requires_login(self, client, db):\n        \"\"\"Test product creation requires authentication.\"\"\"\n        response = client.get(reverse('products:create'))\n\n        assert response.status_code == 302\n        assert response.url.startswith('\u002Faccounts\u002Flogin\u002F')\n\n    def test_product_create_authenticated(self, authenticated_client, db):\n        \"\"\"Test product creation as authenticated user.\"\"\"\n        response = authenticated_client.get(reverse('products:create'))\n\n        assert response.status_code == 200\n\n    def test_product_create_post(self, authenticated_client, db, category):\n        \"\"\"Test creating a product via POST.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'description': 'A test product',\n            'price': '99.99',\n            'stock': 10,\n            'category': category.id,\n        }\n\n        response = authenticated_client.post(reverse('products:create'), data)\n\n        assert response.status_code == 302\n        assert Product.objects.filter(name='Test Product').exists()\n```\n\n## DRF API Testing\n\n### Serializer Testing\n\n```python\n# tests\u002Ftest_serializers.py\nimport pytest\nfrom rest_framework.exceptions import ValidationError\nfrom apps.products.serializers import ProductSerializer\nfrom tests.factories import ProductFactory\n\nclass TestProductSerializer:\n    \"\"\"Test ProductSerializer.\"\"\"\n\n    def test_serialize_product(self, db):\n        \"\"\"Test serializing a product.\"\"\"\n        product = ProductFactory()\n        serializer = ProductSerializer(product)\n\n        data = serializer.data\n\n        assert data['id'] == product.id\n        assert data['name'] == product.name\n        assert data['price'] == str(product.price)\n\n    def test_deserialize_product(self, db):\n        \"\"\"Test deserializing product data.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'description': 'Test description',\n            'price': '99.99',\n            'stock': 10,\n            'category': 1,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert serializer.is_valid()\n        product = serializer.save()\n\n        assert product.name == 'Test Product'\n        assert float(product.price) == 99.99\n\n    def test_price_validation(self, db):\n        \"\"\"Test price validation.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'price': '-10.00',\n            'stock': 10,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert not serializer.is_valid()\n        assert 'price' in serializer.errors\n\n    def test_stock_validation(self, db):\n        \"\"\"Test stock cannot be negative.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'price': '99.99',\n            'stock': -5,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert not serializer.is_valid()\n        assert 'stock' in serializer.errors\n```\n\n### API ViewSet Testing\n\n```python\n# tests\u002Ftest_api.py\nimport pytest\nfrom rest_framework.test import APIClient\nfrom rest_framework import status\nfrom django.urls import reverse\nfrom tests.factories import ProductFactory, UserFactory\n\nclass TestProductAPI:\n    \"\"\"Test Product API endpoints.\"\"\"\n\n    @pytest.fixture\n    def api_client(self):\n        \"\"\"Return API client.\"\"\"\n        return APIClient()\n\n    def test_list_products(self, api_client, db):\n        \"\"\"Test listing products.\"\"\"\n        ProductFactory.create_batch(10)\n\n        url = reverse('api:product-list')\n        response = api_client.get(url)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 10\n\n    def test_retrieve_product(self, api_client, db):\n        \"\"\"Test retrieving a product.\"\"\"\n        product = ProductFactory()\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        response = api_client.get(url)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['id'] == product.id\n\n    def test_create_product_unauthorized(self, api_client, db):\n        \"\"\"Test creating product without authentication.\"\"\"\n        url = reverse('api:product-list')\n        data = {'name': 'Test Product', 'price': '99.99'}\n\n        response = api_client.post(url, data)\n\n        assert response.status_code == status.HTTP_401_UNAUTHORIZED\n\n    def test_create_product_authorized(self, authenticated_api_client, db):\n        \"\"\"Test creating product as authenticated user.\"\"\"\n        url = reverse('api:product-list')\n        data = {\n            'name': 'Test Product',\n            'description': 'Test',\n            'price': '99.99',\n            'stock': 10,\n        }\n\n        response = authenticated_api_client.post(url, data)\n\n        assert response.status_code == status.HTTP_201_CREATED\n        assert response.data['name'] == 'Test Product'\n\n    def test_update_product(self, authenticated_api_client, db):\n        \"\"\"Test updating a product.\"\"\"\n        product = ProductFactory(created_by=authenticated_api_client.user)\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        data = {'name': 'Updated Product'}\n\n        response = authenticated_api_client.patch(url, data)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['name'] == 'Updated Product'\n\n    def test_delete_product(self, authenticated_api_client, db):\n        \"\"\"Test deleting a product.\"\"\"\n        product = ProductFactory(created_by=authenticated_api_client.user)\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        response = authenticated_api_client.delete(url)\n\n        assert response.status_code == status.HTTP_204_NO_CONTENT\n\n    def test_filter_products_by_price(self, api_client, db):\n        \"\"\"Test filtering products by price.\"\"\"\n        ProductFactory(price=50)\n        ProductFactory(price=150)\n\n        url = reverse('api:product-list')\n        response = api_client.get(url, {'price_min': 100})\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 1\n\n    def test_search_products(self, api_client, db):\n        \"\"\"Test searching products.\"\"\"\n        ProductFactory(name='Apple iPhone')\n        ProductFactory(name='Samsung Galaxy')\n\n        url = reverse('api:product-list')\n        response = api_client.get(url, {'search': 'Apple'})\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 1\n```\n\n## Mocking and Patching\n\n### Mocking External Services\n\n```python\n# tests\u002Ftest_views.py\nfrom unittest.mock import patch, Mock\nimport pytest\n\nclass TestPaymentView:\n    \"\"\"Test payment view with mocked payment gateway.\"\"\"\n\n    @patch('apps.payments.services.stripe')\n    def test_successful_payment(self, mock_stripe, client, user, product):\n        \"\"\"Test successful payment with mocked Stripe.\"\"\"\n        # Configure mock\n        mock_stripe.Charge.create.return_value = {\n            'id': 'ch_123',\n            'status': 'succeeded',\n            'amount': 9999,\n        }\n\n        client.force_login(user)\n        response = client.post(reverse('payments:process'), {\n            'product_id': product.id,\n            'token': 'tok_visa',\n        })\n\n        assert response.status_code == 302\n        mock_stripe.Charge.create.assert_called_once()\n\n    @patch('apps.payments.services.stripe')\n    def test_failed_payment(self, mock_stripe, client, user, product):\n        \"\"\"Test failed payment.\"\"\"\n        mock_stripe.Charge.create.side_effect = Exception('Card declined')\n\n        client.force_login(user)\n        response = client.post(reverse('payments:process'), {\n            'product_id': product.id,\n            'token': 'tok_visa',\n        })\n\n        assert response.status_code == 302\n        assert 'error' in response.url\n```\n\n### Mocking Email Sending\n\n```python\n# tests\u002Ftest_email.py\nfrom django.core import mail\nfrom django.test import override_settings\n\n@override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')\ndef test_order_confirmation_email(db, order):\n    \"\"\"Test order confirmation email.\"\"\"\n    order.send_confirmation_email()\n\n    assert len(mail.outbox) == 1\n    assert order.user.email in mail.outbox[0].to\n    assert 'Order Confirmation' in mail.outbox[0].subject\n```\n\n## Integration Testing\n\n### Full Flow Testing\n\n```python\n# tests\u002Ftest_integration.py\nimport pytest\nfrom django.urls import reverse\nfrom tests.factories import UserFactory, ProductFactory\n\nclass TestCheckoutFlow:\n    \"\"\"Test complete checkout flow.\"\"\"\n\n    def test_guest_to_purchase_flow(self, client, db):\n        \"\"\"Test complete flow from guest to purchase.\"\"\"\n        # Step 1: Register\n        response = client.post(reverse('users:register'), {\n            'email': 'test@example.com',\n            'password': 'testpass123',\n            'password_confirm': 'testpass123',\n        })\n        assert response.status_code == 302\n\n        # Step 2: Login\n        response = client.post(reverse('users:login'), {\n            'email': 'test@example.com',\n            'password': 'testpass123',\n        })\n        assert response.status_code == 302\n\n        # Step 3: Browse products\n        product = ProductFactory(price=100)\n        response = client.get(reverse('products:detail', kwargs={'slug': product.slug}))\n        assert response.status_code == 200\n\n        # Step 4: Add to cart\n        response = client.post(reverse('cart:add'), {\n            'product_id': product.id,\n            'quantity': 1,\n        })\n        assert response.status_code == 302\n\n        # Step 5: Checkout\n        response = client.get(reverse('checkout:review'))\n        assert response.status_code == 200\n        assert product.name in response.content.decode()\n\n        # Step 6: Complete purchase\n        with patch('apps.checkout.services.process_payment') as mock_payment:\n            mock_payment.return_value = True\n            response = client.post(reverse('checkout:complete'))\n\n        assert response.status_code == 302\n        assert Order.objects.filter(user__email='test@example.com').exists()\n```\n\n## Testing Best Practices\n\n### DO\n\n- **Use factories**: Instead of manual object creation\n- **One assertion per test**: Keep tests focused\n- **Descriptive test names**: `test_user_cannot_delete_others_post`\n- **Test edge cases**: Empty inputs, None values, boundary conditions\n- **Mock external services**: Don't depend on external APIs\n- **Use fixtures**: Eliminate duplication\n- **Test permissions**: Ensure authorization works\n- **Keep tests fast**: Use `--reuse-db` and `--nomigrations`\n\n### DON'T\n\n- **Don't test Django internals**: Trust Django to work\n- **Don't test third-party code**: Trust libraries to work\n- **Don't ignore failing tests**: All tests must pass\n- **Don't make tests dependent**: Tests should run in any order\n- **Don't over-mock**: Mock only external dependencies\n- **Don't test private methods**: Test public interface\n- **Don't use production database**: Always use test database\n\n## Coverage\n\n### Coverage Configuration\n\n```bash\n# Run tests with coverage\npytest --cov=apps --cov-report=html --cov-report=term-missing\n\n# Generate HTML report\nopen htmlcov\u002Findex.html\n```\n\n### Coverage Goals\n\n| Component | Target Coverage |\n|-----------|-----------------|\n| Models | 90%+ |\n| Serializers | 85%+ |\n| Views | 80%+ |\n| Services | 90%+ |\n| Utilities | 80%+ |\n| Overall | 80%+ |\n\n## Quick Reference\n\n| Pattern | Usage |\n|---------|-------|\n| `@pytest.mark.django_db` | Enable database access |\n| `client` | Django test client |\n| `api_client` | DRF API client |\n| `factory.create_batch(n)` | Create multiple objects |\n| `patch('module.function')` | Mock external dependencies |\n| `override_settings` | Temporarily change settings |\n| `force_authenticate()` | Bypass authentication in tests |\n| `assertRedirects` | Check for redirects |\n| `assertTemplateUsed` | Verify template usage |\n| `mail.outbox` | Check sent emails |\n\nRemember: Tests are documentation. Good tests explain how your code should work. Keep them simple, readable, and maintainable.\n","# Django Testing with TDD\n\nTest-driven development for Django applications using pytest, factory_boy, and Django REST Framework.\n\n## When to Activate\n\n- Writing new Django applications\n- Implementing Django REST Framework APIs\n- Testing Django models, views, and serializers\n- Setting up testing infrastructure for Django projects\n\n## TDD Workflow for Django\n\n### Red-Green-Refactor Cycle\n\n```python\n# Step 1: RED - Write failing test\ndef test_user_creation():\n    user = User.objects.create_user(email='test@example.com', password='testpass123')\n    assert user.email == 'test@example.com'\n    assert user.check_password('testpass123')\n    assert not user.is_staff\n\n# Step 2: GREEN - Make test pass\n# Create User model or factory\n\n# Step 3: REFACTOR - Improve while keeping tests green\n```\n\n## Setup\n\n### pytest Configuration\n\n```ini\n# pytest.ini\n[pytest]\nDJANGO_SETTINGS_MODULE = config.settings.test\ntestpaths = tests\npython_files = test_*.py\npython_classes = Test*\npython_functions = test_*\naddopts =\n    --reuse-db\n    --nomigrations\n    --cov=apps\n    --cov-report=html\n    --cov-report=term-missing\n    --strict-markers\nmarkers =\n    slow: marks tests as slow\n    integration: marks tests as integration tests\n```\n\n### Test Settings\n\n```python\n# config\u002Fsettings\u002Ftest.py\nfrom .base import *\n\nDEBUG = True\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.sqlite3',\n        'NAME': ':memory:',\n    }\n}\n\n# Disable migrations for speed\nclass DisableMigrations:\n    def __contains__(self, item):\n        return True\n\n    def __getitem__(self, item):\n        return None\n\nMIGRATION_MODULES = DisableMigrations()\n\n# Faster password hashing\nPASSWORD_HASHERS = [\n    'django.contrib.auth.hashers.MD5PasswordHasher',\n]\n\n# Email backend\nEMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n\n# Celery always eager\nCELERY_TASK_ALWAYS_EAGER = True\nCELERY_TASK_EAGER_PROPAGATES = True\n```\n\n### conftest.py\n\n```python\n# tests\u002Fconftest.py\nimport pytest\nfrom django.utils import timezone\nfrom django.contrib.auth import get_user_model\n\nUser = get_user_model()\n\n@pytest.fixture(autouse=True)\ndef timezone_settings(settings):\n    \"\"\"Ensure consistent timezone.\"\"\"\n    settings.TIME_ZONE = 'UTC'\n\n@pytest.fixture\ndef user(db):\n    \"\"\"Create a test user.\"\"\"\n    return User.objects.create_user(\n        email='test@example.com',\n        password='testpass123',\n        username='testuser'\n    )\n\n@pytest.fixture\ndef admin_user(db):\n    \"\"\"Create an admin user.\"\"\"\n    return User.objects.create_superuser(\n        email='admin@example.com',\n        password='adminpass123',\n        username='admin'\n    )\n\n@pytest.fixture\ndef authenticated_client(client, user):\n    \"\"\"Return authenticated client.\"\"\"\n    client.force_login(user)\n    return client\n\n@pytest.fixture\ndef api_client():\n    \"\"\"Return DRF API client.\"\"\"\n    from rest_framework.test import APIClient\n    return APIClient()\n\n@pytest.fixture\ndef authenticated_api_client(api_client, user):\n    \"\"\"Return authenticated API client.\"\"\"\n    api_client.force_authenticate(user=user)\n    return api_client\n```\n\n## Factory Boy\n\n### Factory Setup\n\n```python\n# tests\u002Ffactories.py\nimport factory\nfrom factory import fuzzy\nfrom datetime import datetime, timedelta\nfrom django.contrib.auth import get_user_model\nfrom apps.products.models import Product, Category\n\nUser = get_user_model()\n\nclass UserFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for User model.\"\"\"\n\n    class Meta:\n        model = User\n\n    email = factory.Sequence(lambda n: f\"user{n}@example.com\")\n    username = factory.Sequence(lambda n: f\"user{n}\")\n    password = factory.PostGenerationMethodCall('set_password', 'testpass123')\n    first_name = factory.Faker('first_name')\n    last_name = factory.Faker('last_name')\n    is_active = True\n\nclass CategoryFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for Category model.\"\"\"\n\n    class Meta:\n        model = Category\n\n    name = factory.Faker('word')\n    slug = factory.LazyAttribute(lambda obj: obj.name.lower())\n    description = factory.Faker('text')\n\nclass ProductFactory(factory.django.DjangoModelFactory):\n    \"\"\"Factory for Product model.\"\"\"\n\n    class Meta:\n        model = Product\n\n    name = factory.Faker('sentence', nb_words=3)\n    slug = factory.LazyAttribute(lambda obj: obj.name.lower().replace(' ', '-'))\n    description = factory.Faker('text')\n    price = fuzzy.FuzzyDecimal(10.00, 1000.00, 2)\n    stock = fuzzy.FuzzyInteger(0, 100)\n    is_active = True\n    category = factory.SubFactory(CategoryFactory)\n    created_by = factory.SubFactory(UserFactory)\n\n    @factory.post_generation\n    def tags(self, create, extracted, **kwargs):\n        \"\"\"Add tags to product.\"\"\"\n        if not create:\n            return\n        if extracted:\n            for tag in extracted:\n                self.tags.add(tag)\n```\n\n### Using Factories\n\n```python\n# tests\u002Ftest_models.py\nimport pytest\nfrom tests.factories import ProductFactory, UserFactory\n\ndef test_product_creation():\n    \"\"\"Test product creation using factory.\"\"\"\n    product = ProductFactory(price=100.00, stock=50)\n    assert product.price == 100.00\n    assert product.stock == 50\n    assert product.is_active is True\n\ndef test_product_with_tags():\n    \"\"\"Test product with tags.\"\"\"\n    tags = [TagFactory(name='electronics'), TagFactory(name='new')]\n    product = ProductFactory(tags=tags)\n    assert product.tags.count() == 2\n\ndef test_multiple_products():\n    \"\"\"Test creating multiple products.\"\"\"\n    products = ProductFactory.create_batch(10)\n    assert len(products) == 10\n```\n\n## Model Testing\n\n### Model Tests\n\n```python\n# tests\u002Ftest_models.py\nimport pytest\nfrom django.core.exceptions import ValidationError\nfrom tests.factories import UserFactory, ProductFactory\n\nclass TestUserModel:\n    \"\"\"Test User model.\"\"\"\n\n    def test_create_user(self, db):\n        \"\"\"Test creating a regular user.\"\"\"\n        user = UserFactory(email='test@example.com')\n        assert user.email == 'test@example.com'\n        assert user.check_password('testpass123')\n        assert not user.is_staff\n        assert not user.is_superuser\n\n    def test_create_superuser(self, db):\n        \"\"\"Test creating a superuser.\"\"\"\n        user = UserFactory(\n            email='admin@example.com',\n            is_staff=True,\n            is_superuser=True\n        )\n        assert user.is_staff\n        assert user.is_superuser\n\n    def test_user_str(self, db):\n        \"\"\"Test user string representation.\"\"\"\n        user = UserFactory(email='test@example.com')\n        assert str(user) == 'test@example.com'\n\nclass TestProductModel:\n    \"\"\"Test Product model.\"\"\"\n\n    def test_product_creation(self, db):\n        \"\"\"Test creating a product.\"\"\"\n        product = ProductFactory()\n        assert product.id is not None\n        assert product.is_active is True\n        assert product.created_at is not None\n\n    def test_product_slug_generation(self, db):\n        \"\"\"Test automatic slug generation.\"\"\"\n        product = ProductFactory(name='Test Product')\n        assert product.slug == 'test-product'\n\n    def test_product_price_validation(self, db):\n        \"\"\"Test price cannot be negative.\"\"\"\n        product = ProductFactory(price=-10)\n        with pytest.raises(ValidationError):\n            product.full_clean()\n\n    def test_product_manager_active(self, db):\n        \"\"\"Test active manager method.\"\"\"\n        ProductFactory.create_batch(5, is_active=True)\n        ProductFactory.create_batch(3, is_active=False)\n\n        active_count = Product.objects.active().count()\n        assert active_count == 5\n\n    def test_product_stock_management(self, db):\n        \"\"\"Test stock management.\"\"\"\n        product = ProductFactory(stock=10)\n        product.reduce_stock(5)\n        product.refresh_from_db()\n        assert product.stock == 5\n\n        with pytest.raises(ValueError):\n            product.reduce_stock(10)  # Not enough stock\n```\n\n## View Testing\n\n### Django View Testing\n\n```python\n# tests\u002Ftest_views.py\nimport pytest\nfrom django.urls import reverse\nfrom tests.factories import ProductFactory, UserFactory\n\nclass TestProductViews:\n    \"\"\"Test product views.\"\"\"\n\n    def test_product_list(self, client, db):\n        \"\"\"Test product list view.\"\"\"\n        ProductFactory.create_batch(10)\n\n        response = client.get(reverse('products:list'))\n\n        assert response.status_code == 200\n        assert len(response.context['products']) == 10\n\n    def test_product_detail(self, client, db):\n        \"\"\"Test product detail view.\"\"\"\n        product = ProductFactory()\n\n        response = client.get(reverse('products:detail', kwargs={'slug': product.slug}))\n\n        assert response.status_code == 200\n        assert response.context['product'] == product\n\n    def test_product_create_requires_login(self, client, db):\n        \"\"\"Test product creation requires authentication.\"\"\"\n        response = client.get(reverse('products:create'))\n\n        assert response.status_code == 302\n        assert response.url.startswith('\u002Faccounts\u002Flogin\u002F')\n\n    def test_product_create_authenticated(self, authenticated_client, db):\n        \"\"\"Test product creation as authenticated user.\"\"\"\n        response = authenticated_client.get(reverse('products:create'))\n\n        assert response.status_code == 200\n\n    def test_product_create_post(self, authenticated_client, db, category):\n        \"\"\"Test creating a product via POST.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'description': 'A test product',\n            'price': '99.99',\n            'stock': 10,\n            'category': category.id,\n        }\n\n        response = authenticated_client.post(reverse('products:create'), data)\n\n        assert response.status_code == 302\n        assert Product.objects.filter(name='Test Product').exists()\n```\n\n## DRF API Testing\n\n### Serializer Testing\n\n```python\n# tests\u002Ftest_serializers.py\nimport pytest\nfrom rest_framework.exceptions import ValidationError\nfrom apps.products.serializers import ProductSerializer\nfrom tests.factories import ProductFactory\n\nclass TestProductSerializer:\n    \"\"\"Test ProductSerializer.\"\"\"\n\n    def test_serialize_product(self, db):\n        \"\"\"Test serializing a product.\"\"\"\n        product = ProductFactory()\n        serializer = ProductSerializer(product)\n\n        data = serializer.data\n\n        assert data['id'] == product.id\n        assert data['name'] == product.name\n        assert data['price'] == str(product.price)\n\n    def test_deserialize_product(self, db):\n        \"\"\"Test deserializing product data.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'description': 'Test description',\n            'price': '99.99',\n            'stock': 10,\n            'category': 1,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert serializer.is_valid()\n        product = serializer.save()\n\n        assert product.name == 'Test Product'\n        assert float(product.price) == 99.99\n\n    def test_price_validation(self, db):\n        \"\"\"Test price validation.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'price': '-10.00',\n            'stock': 10,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert not serializer.is_valid()\n        assert 'price' in serializer.errors\n\n    def test_stock_validation(self, db):\n        \"\"\"Test stock cannot be negative.\"\"\"\n        data = {\n            'name': 'Test Product',\n            'price': '99.99',\n            'stock': -5,\n        }\n\n        serializer = ProductSerializer(data=data)\n\n        assert not serializer.is_valid()\n        assert 'stock' in serializer.errors\n```\n\n### API ViewSet Testing\n\n```python\n# tests\u002Ftest_api.py\nimport pytest\nfrom rest_framework.test import APIClient\nfrom rest_framework import status\nfrom django.urls import reverse\nfrom tests.factories import ProductFactory, UserFactory\n\nclass TestProductAPI:\n    \"\"\"Test Product API endpoints.\"\"\"\n\n    @pytest.fixture\n    def api_client(self):\n        \"\"\"Return API client.\"\"\"\n        return APIClient()\n\n    def test_list_products(self, api_client, db):\n        \"\"\"Test listing products.\"\"\"\n        ProductFactory.create_batch(10)\n\n        url = reverse('api:product-list')\n        response = api_client.get(url)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 10\n\n    def test_retrieve_product(self, api_client, db):\n        \"\"\"Test retrieving a product.\"\"\"\n        product = ProductFactory()\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        response = api_client.get(url)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['id'] == product.id\n\n    def test_create_product_unauthorized(self, api_client, db):\n        \"\"\"Test creating product without authentication.\"\"\"\n        url = reverse('api:product-list')\n        data = {'name': 'Test Product', 'price': '99.99'}\n\n        response = api_client.post(url, data)\n\n        assert response.status_code == status.HTTP_401_UNAUTHORIZED\n\n    def test_create_product_authorized(self, authenticated_api_client, db):\n        \"\"\"Test creating product as authenticated user.\"\"\"\n        url = reverse('api:product-list')\n        data = {\n            'name': 'Test Product',\n            'description': 'Test',\n            'price': '99.99',\n            'stock': 10,\n        }\n\n        response = authenticated_api_client.post(url, data)\n\n        assert response.status_code == status.HTTP_201_CREATED\n        assert response.data['name'] == 'Test Product'\n\n    def test_update_product(self, authenticated_api_client, db):\n        \"\"\"Test updating a product.\"\"\"\n        product = ProductFactory(created_by=authenticated_api_client.user)\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        data = {'name': 'Updated Product'}\n\n        response = authenticated_api_client.patch(url, data)\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['name'] == 'Updated Product'\n\n    def test_delete_product(self, authenticated_api_client, db):\n        \"\"\"Test deleting a product.\"\"\"\n        product = ProductFactory(created_by=authenticated_api_client.user)\n\n        url = reverse('api:product-detail', kwargs={'pk': product.id})\n        response = authenticated_api_client.delete(url)\n\n        assert response.status_code == status.HTTP_204_NO_CONTENT\n\n    def test_filter_products_by_price(self, api_client, db):\n        \"\"\"Test filtering products by price.\"\"\"\n        ProductFactory(price=50)\n        ProductFactory(price=150)\n\n        url = reverse('api:product-list')\n        response = api_client.get(url, {'price_min': 100})\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 1\n\n    def test_search_products(self, api_client, db):\n        \"\"\"Test searching products.\"\"\"\n        ProductFactory(name='Apple iPhone')\n        ProductFactory(name='Samsung Galaxy')\n\n        url = reverse('api:product-list')\n        response = api_client.get(url, {'search': 'Apple'})\n\n        assert response.status_code == status.HTTP_200_OK\n        assert response.data['count'] == 1\n```\n\n## Mocking and Patching\n\n### Mocking External Services\n\n```python\n# tests\u002Ftest_views.py\nfrom unittest.mock import patch, Mock\nimport pytest\n\nclass TestPaymentView:\n    \"\"\"Test payment view with mocked payment gateway.\"\"\"\n\n    @patch('apps.payments.services.stripe')\n    def test_successful_payment(self, mock_stripe, client, user, product):\n        \"\"\"Test successful payment with mocked Stripe.\"\"\"\n        # Configure mock\n        mock_stripe.Charge.create.return_value = {\n            'id': 'ch_123',\n            'status': 'succeeded',\n            'amount': 9999,\n        }\n\n        client.force_login(user)\n        response = client.post(reverse('payments:process'), {\n            'product_id': product.id,\n            'token': 'tok_visa',\n        })\n\n        assert response.status_code == 302\n        mock_stripe.Charge.create.assert_called_once()\n\n    @patch('apps.payments.services.stripe')\n    def test_failed_payment(self, mock_stripe, client, user, product):\n        \"\"\"Test failed payment.\"\"\"\n        mock_stripe.Charge.create.side_effect = Exception('Card declined')\n\n        client.force_login(user)\n        response = client.post(reverse('payments:process'), {\n            'product_id': product.id,\n            'token': 'tok_visa',\n        })\n\n        assert response.status_code == 302\n        assert 'error' in response.url\n```\n\n### Mocking Email Sending\n\n```python\n# tests\u002Ftest_email.py\nfrom django.core import mail\nfrom django.test import override_settings\n\n@override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend')\ndef test_order_confirmation_email(db, order):\n    \"\"\"Test order confirmation email.\"\"\"\n    order.send_confirmation_email()\n\n    assert len(mail.outbox) == 1\n    assert order.user.email in mail.outbox[0].to\n    assert 'Order Confirmation' in mail.outbox[0].subject\n```\n\n## Integration Testing\n\n### Full Flow Testing\n\n```python\n# tests\u002Ftest_integration.py\nimport pytest\nfrom django.urls import reverse\nfrom tests.factories import UserFactory, ProductFactory\n\nclass TestCheckoutFlow:\n    \"\"\"Test complete checkout flow.\"\"\"\n\n    def test_guest_to_purchase_flow(self, client, db):\n        \"\"\"Test complete flow from guest to purchase.\"\"\"\n        # Step 1: Register\n        response = client.post(reverse('users:register'), {\n            'email': 'test@example.com',\n            'password': 'testpass123',\n            'password_confirm': 'testpass123',\n        })\n        assert response.status_code == 302\n\n        # Step 2: Login\n        response = client.post(reverse('users:login'), {\n            'email': 'test@example.com',\n            'password': 'testpass123',\n        })\n        assert response.status_code == 302\n\n        # Step 3: Browse products\n        product = ProductFactory(price=100)\n        response = client.get(reverse('products:detail', kwargs={'slug': product.slug}))\n        assert response.status_code == 200\n\n        # Step 4: Add to cart\n        response = client.post(reverse('cart:add'), {\n            'product_id': product.id,\n            'quantity': 1,\n        })\n        assert response.status_code == 302\n\n        # Step 5: Checkout\n        response = client.get(reverse('checkout:review'))\n        assert response.status_code == 200\n        assert product.name in response.content.decode()\n\n        # Step 6: Complete purchase\n        with patch('apps.checkout.services.process_payment') as mock_payment:\n            mock_payment.return_value = True\n            response = client.post(reverse('checkout:complete'))\n\n        assert response.status_code == 302\n        assert Order.objects.filter(user__email='test@example.com').exists()\n```\n\n## Testing Best Practices\n\n### DO\n\n- **Use factories**: Instead of manual object creation\n- **One assertion per test**: Keep tests focused\n- **Descriptive test names**: `test_user_cannot_delete_others_post`\n- **Test edge cases**: Empty inputs, None values, boundary conditions\n- **Mock external services**: Don't depend on external APIs\n- **Use fixtures**: Eliminate duplication\n- **Test permissions**: Ensure authorization works\n- **Keep tests fast**: Use `--reuse-db` and `--nomigrations`\n\n### DON'T\n\n- **Don't test Django internals**: Trust Django to work\n- **Don't test third-party code**: Trust libraries to work\n- **Don't ignore failing tests**: All tests must pass\n- **Don't make tests dependent**: Tests should run in any order\n- **Don't over-mock**: Mock only external dependencies\n- **Don't test private methods**: Test public interface\n- **Don't use production database**: Always use test database\n\n## Coverage\n\n### Coverage Configuration\n\n```bash\n# Run tests with coverage\npytest --cov=apps --cov-report=html --cov-report=term-missing\n\n# Generate HTML report\nopen htmlcov\u002Findex.html\n```\n\n### Coverage Goals\n\n| Component | Target Coverage |\n|-----------|-----------------|\n| Models | 90%+ |\n| Serializers | 85%+ |\n| Views | 80%+ |\n| Services | 90%+ |\n| Utilities | 80%+ |\n| Overall | 80%+ |\n\n## Quick Reference\n\n| Pattern | Usage |\n|---------|-------|\n| `@pytest.mark.django_db` | Enable database access |\n| `client` | Django test client |\n| `api_client` | DRF API client |\n| `factory.create_batch(n)` | Create multiple objects |\n| `patch('module.function')` | Mock external dependencies |\n| `override_settings` | Temporarily change settings |\n| `force_authenticate()` | Bypass authentication in tests |\n| `assertRedirects` | Check for redirects |\n| `assertTemplateUsed` | Verify template usage |\n| `mail.outbox` | Check sent emails |\n\nRemember: Tests are documentation. Good tests explain how your code should work. Keep them simple, readable, and maintainable.\n",{"name":5,"origin":40,"description":7},"ECC","main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Flibrary\u002Fskills\u002Fdjango-tdd","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":48,"prompt":58,"zipAvailable":59},[49,52,55],{"tool":50,"command":51},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-tdd",{"tool":53,"command":54},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-tdd",{"tool":56,"command":57},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-tdd","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-tdd\u002FSKILL.md",true,[],[62,84,113,138,152,168],{"skillNo":63,"name":64,"nameZh":6,"description":65,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":68,"publishedAt":35},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[69,70,71,72,73,74,75,76,77,78,79,80,81,82,83],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","use","context","repo","injection","execution","file",{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":93,"publishedAt":35},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[90],{"categoryNo":91,"categoryName":92,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[94,95,96,97,98,99,100,101,102,103,104,105,106,107,78,108,109,110,111,112],"openmm md","how","decision","pick","linux","analyze","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":114,"name":115,"nameZh":6,"description":116,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":117,"categories":118,"keywords":123,"publishedAt":35},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[119,122],{"categoryNo":120,"categoryName":121,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[124,125,126,127,128,129,130,131,132,133,95,134,135,136,137],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":144,"publishedAt":35},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[140,145,146,147,148,149,150,151],"setup","report","project","installation","project setup","issues","state",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":159,"publishedAt":35},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[158],{"categoryNo":91,"categoryName":92,"taxonomyType":21,"taxonomyTypeDesc":22},[154,160,74,161,162,163,78,164,165,166,167],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":169,"name":145,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":35},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[145,147,110,174,149,175],"files","interactive"]