DEV Community

Ajit Kumar
Ajit Kumar

Posted on

Django + DRF Practical Testing: Blog, Writer, Category, SocialMediaMeta (Full Use Case) - Part 2

In Part 1, we configured pytest, created a test database, and set up fixtures.

Now we focus on real test cases using the following models:

  • Writer
  • Category
  • Blog
  • SocialMediaMeta (auto-created via signal when a blog is published)

1. Example Models

Writer

class Writer(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
Enter fullscreen mode Exit fullscreen mode

Category

class Category(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
Enter fullscreen mode Exit fullscreen mode

SocialMediaMeta

class SocialMediaMeta(models.Model):
    blog = models.OneToOneField("Blog", on_delete=models.CASCADE, related_name="social")
    twitter_title = models.CharField(max_length=255)
    facebook_description = models.TextField()
Enter fullscreen mode Exit fullscreen mode

Blog

class Blog(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    writer = models.ForeignKey(Writer, on_delete=models.PROTECT)
    category = models.ForeignKey(Category, on_delete=models.PROTECT)
    published = models.BooleanField(default=False)
Enter fullscreen mode Exit fullscreen mode

2. Signal That Auto-Creates Metadata

@receiver(post_save, sender=Blog)
def create_social_media_meta(sender, instance, created, **kwargs):
    if created and instance.published:
        SocialMediaMeta.objects.create(
            blog=instance,
            twitter_title=instance.title[:70],
            facebook_description=instance.content[:200],
        )
Enter fullscreen mode Exit fullscreen mode

We will test whether this works.


3. Test Case 1 — Create Blog (Basic FK Handling)

@pytest.mark.django_db
def test_blog_creation(api_client, writer, category):
    payload = {
        "title": "Deep Dive into Django Testing",
        "content": "This article explains...",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }

    response = api_client.post("/api/blogs/", payload, format="json")

    assert response.status_code == 201, response.json()
    assert response.json()["title"] == payload["title"]
Enter fullscreen mode Exit fullscreen mode

4. Test Case 2 — Test Signal Execution

@pytest.mark.django_db
def test_published_blog_creates_social_meta(api_client, writer, category):
    payload = {
        "title": "Signal Test Blog",
        "content": "Testing signal logic...",
        "writer": writer.id,
        "category": category.id,
        "published": True,
    }

    response = api_client.post("/api/blogs/", payload, format="json")
    assert response.status_code == 201

    blog_id = response.json()["id"]

    detail = api_client.get(f"/api/blogs/{blog_id}/").json()

    assert "social" in detail
    assert detail["social"]["twitter_title"] == payload["title"][:70]
Enter fullscreen mode Exit fullscreen mode

5. Test Case 3 — Listing Blogs with Filter

@pytest.mark.django_db
def test_blog_list_filter_by_category(api_client, writer, category):
    api_client.post("/api/blogs/", {
        "title": "A",
        "content": "AAA",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }, format="json")

    api_client.post("/api/blogs/", {
        "title": "B",
        "content": "BBB",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }, format="json")

    response = api_client.get("/api/blogs/?category=tech")

    assert response.status_code == 200
    assert len(response.json()) == 2
Enter fullscreen mode Exit fullscreen mode

6. Test Case 4 — Nested JSON Response

@pytest.mark.django_db
def test_blog_detail_nested(api_client, writer, category):
    blog = api_client.post("/api/blogs/", {
        "title": "Nested Blog",
        "content": "Testing nested serializer logic.",
        "writer": writer.id,
        "category": category.id,
        "published": True
    }, format="json").json()

    detail = api_client.get(f"/api/blogs/{blog['id']}/").json()

    assert detail["writer"]["name"] == writer.name
    assert detail["category"]["title"] == category.title
    assert "social" in detail
Enter fullscreen mode Exit fullscreen mode

7. Test Case 5 — Update Blog

@pytest.mark.django_db
def test_blog_update(api_client, writer, category):
    blog = api_client.post("/api/blogs/", {
        "title": "Old Title",
        "content": "Old content",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }, format="json").json()

    response = api_client.patch(
        f"/api/blogs/{blog['id']}/",
        {"title": "Updated Title"},
        format="json"
    )

    assert response.status_code == 200
    assert response.json()["title"] == "Updated Title"
Enter fullscreen mode Exit fullscreen mode

8. Test Case 6 — Validation Error (Invalid FK)

@pytest.mark.django_db
def test_blog_invalid_writer(api_client, category):
    payload = {
        "title": "Invalid Blog",
        "content": "Fails",
        "writer": 999999,
        "category": category.id,
        "published": False,
    }

    response = api_client.post("/api/blogs/", payload, format="json")

    assert response.status_code == 400
    assert "writer" in response.json()["errors"]
Enter fullscreen mode Exit fullscreen mode

9. Test Case 7 — Reverse FK Test

@pytest.mark.django_db
def test_writer_blog_count(api_client, writer, category):
    api_client.post("/api/blogs/", {
        "title": "Blog1",
        "content": "AAA",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }, format="json")

    api_client.post("/api/blogs/", {
        "title": "Blog2",
        "content": "BBB",
        "writer": writer.id,
        "category": category.id,
        "published": False
    }, format="json")

    response = api_client.get(f"/api/writers/{writer.id}/blogs/")

    assert len(response.json()) == 2
Enter fullscreen mode Exit fullscreen mode

Final Checklist (Both Parts in One Summary)

Setup (Part 1)

✓ Install pytest and plugins
✓ Create pytest.ini
✓ Create settings/test.py
✓ Set up PostgreSQL test_db
✓ Add fixtures (user, API client, writer, category)
✓ Handle custom users
✓ Ensure DRF authentication bypasses login

Use Cases (Part 2)

✓ Test FK creation (Writer, Category → Blog)
✓ Test signals creating related metadata
✓ Test nested JSON responses
✓ Test list endpoints and filters
✓ Test validation errors
✓ Test patch/update flows
✓ Test reverse FK relationships
✓ Use authenticated API requests

Top comments (0)