Python API Development with FastAPI

Testing

Test Create Post

In this article, we review a comprehensive suite of tests for our post endpoints. These tests ensure that unauthorized users cannot access posts, non-existent posts return appropriate status codes, posts are successfully created via the API, and that the default published value is correctly applied when not provided.

The sections below group the tests logically to improve readability and SEO. Each section includes detailed explanations and corresponding code blocks.


Unauthorized Access and Retrieve Post Tests

The tests in this section verify that:

  • Unauthorized users cannot retrieve posts.
  • Requests for non-existing posts return a 404 status code.
  • Authorized users can successfully retrieve an existing post with matching attributes.
def test_unauthorized_user_get_one_post(client, test_posts):
    res = client.get(f"/posts/{test_posts[0].id}")
    assert res.status_code == 401


def test_get_one_post_not_exist(authorized_client, test_posts):
    res = authorized_client.get(f"/posts/88888")
    assert res.status_code == 404


def test_get_one_post(authorized_client, test_posts):
    res = authorized_client.get(f"/posts/{test_posts[0].id}")
    post = schemas.PostOut(**res.json())
    assert post.id == test_posts[0].id
    assert post.title == test_posts[0].title
    assert post.content == test_posts[0].content

Create Post Tests

This section tests the post creation functionality using parameterization. It verifies that:

  • The correct HTTP status code (201) is returned.
  • The post content matches the input.
  • The owner ID of the post is correctly assigned.
import pytest

@pytest.mark.parametrize("title, content, published", [
    ("awesome new title", "awesome new content", True),
    ("favorite pizza", "i love pepperoni", False),
    ("tallest skyscrapers", "wahoo", True),
])
def test_create_post(authorized_client, test_user, test_posts, title, content, published):
    res = authorized_client.post("/posts/", json={
        "title": title,
        "content": content,
        "published": published
    })
    created_post = schemas.Post(**res.json())
    assert res.status_code == 201
    assert created_post.title == title
    assert created_post.content == content
    assert created_post.published == published
    assert created_post.owner_id == test_user['id']

Default Published Value Test

Note

In the PostBase model, the "published" field defaults to True. This test confirms that when the "published" field is omitted, the system sets it to True by default.

def test_create_post_default_published_true(authorized_client, test_user, test_posts):
    res = authorized_client.post("/posts/", json={
        "title": "arbitrary title",
        "content": "aasdfjasdf"
    })
    
    created_post = schemas.Post(**res.json())
    assert res.status_code == 201
    assert created_post.title == "arbitrary title"
    assert created_post.content == "aasdfjasdf"
    assert created_post.published is True
    assert created_post.owner_id == test_user['id']

Unauthorized Post Creation Test

This test confirms that only authorized users can create posts. Any attempt by an unauthorized user to access the post route will result in a 401 status code.

def test_unauthorized_user_create_post(client, test_user, test_posts):
    res = client.get("/posts/")
    assert res.status_code == 401

Pydantic Schemas for Posts and Users

The following Pydantic schemas define the structure for posts and users used in the tests. Notice that the "published" attribute in the PostBase model defaults to True.

from pydantic import BaseModel, EmailStr
from datetime import datetime

class PostBase(BaseModel):
    title: str
    content: str
    published: bool = True

class PostCreate(PostBase):
    pass

class Post(PostBase):
    id: int
    created_at: datetime

    class Config:
        orm_mode = True

class UserOut(BaseModel):
    id: int
    email: EmailStr
    created_at: datetime

    class Config:
        orm_mode = True

Conclusion

At this stage, all tests related to post creation have been implemented and verified, including:

  • Validating unauthorized access attempts.
  • Handling requests for non-existent posts.
  • Confirming the correct creation of posts.
  • Ensuring default values are set appropriately when omitted.

In the next article, we will explore tests for updating or deleting a post.

Warning

Note: Additional console warnings regarding external library deprecations, such as the @coroutine decorator warning from aiofiles, do not affect the test outcomes.

Additional console warnings may include:

=================================================================
warnings summary
=================================================================
/venv/lib/site-packages/aiofiles/os.py:10: DeprecationWarning: "@coroutine" decorator
  ...

This concludes our lesson on testing post creation functionality. For more details, refer to our API Testing Documentation.

Watch Video

Watch video content

Previous
Get One Post Test