본문 바로가기
개발/웹

Django 커머스 보일러플레이트 - (3) 유닛 테스트, drf-yasg API 문서화

by pandatta 2023. 5. 2.

Django 커머스 보일러플레이트 시리즈

(1) 프로젝트 요구사항과 다이어그램 모델링
(2) 장고/DRF 모델, 시리얼라이저, 뷰
(3) 유닛 테스트, drf-yasg API 문서화
(4) Nginx 웹 서버와 도커 컴포즈, AWS ECS 배포
(5) GitHub Actions CI/CD

안녕하세요, 판다타입니다.

한동안 파이썬 웹 프레임워크 삼대장 플라스크(Flask), 장고(Django), 패스트API(FastAPI) 중, 회사에서는 사용하지 않는 장고를 이용해 e-커머스(e-commerce) 제작에 사용할 수 있는 보일러플레이트(boilerplate)를 만들어보았습니다. 진행한지는 꽤 되어서 한꺼번에 몰아서 작성하다보니 자세한 설명을 하기는 어렵고... 여러분의 장고 프로젝트 작성에 도움이 될까 하여 간단하게 몇 가지를 정리해보았습니다. 자세한 소스코드는 Djarf GitHub 저장소를 참고해주시고, 궁금한 점은 댓글이나 메일로 문의해주세요.

DRF 유닛 테스트 (DRF 공식 테스팅 문서 참고)

# commerce/tests_commerce/test_order.py, 다른 모델도 다 별도 유닛 테스트가 있음
from rest_framework.status import (
    HTTP_200_OK,
    HTTP_201_CREATED,
    HTTP_204_NO_CONTENT,
)
from rest_framework.test import APITestCase
from commerce.models import Cart, Category, Order, Order2Product, Product
from common.models import User

class OrderTests(APITestCase):
    def setUp(self):  # 테스트를 위한 모킹 고객, 상품, ... 데이터베이스 생성
        user1 = User.objects.create(username="user1")
        user2 = User.objects.create(username="user2")
        self.client.force_authenticate(user=user2)

        category = Category.objects.create(title="category")
        product1 = Product.objects.create(
            vendor=user1, category=category, title="product1", price=1
        )
        product2 = Product.objects.create(
            vendor=user1, category=category, title="product2", price=2
        )

        order = Order.objects.create(customer=user2)
        _ = Order2Product.objects.create(
            order=order, product=product1, quantity=1
        )
        _ = Order2Product.objects.create(
            order=order, product=product2, quantity=2
        )

        _ = Cart.objects.create(customer=user2, product=product1, quantity=2)
        _ = Cart.objects.create(customer=user2, product=product2, quantity=3)

    def test_list_order(self):  # 리스트 뷰
        response = self.client.get(
            "/commerce/orders/", data=None, format="json"
        )

        self.assertEqual(response.status_code, HTTP_200_OK)
        self.assertEqual(response.data["count"], 1)

    def test_create_order(self):  # 생성 뷰
        response = self.client.post(
            "/commerce/orders/", data=None, format="json"
        )

        self.assertEqual(response.status_code, HTTP_201_CREATED)
        self.assertEqual(Order.objects.all().count(), 2)
        self.assertEqual(Order2Product.objects.all().count(), 4)
        self.assertEqual(Cart.objects.all().count(), 0)

    def test_retrieve_order(self):  # 가져오기 뷰
        response = self.client.get(
            "/commerce/orders/1/", data=None, format="json"
        )

        self.assertEqual(response.status_code, HTTP_200_OK)
        self.assertEqual(
            response.data["customer"], "http://testserver/common/users/2/"
        )

    def test_destroy_order(self):  # 삭제 뷰
        response = self.client.delete(
            "/commerce/orders/1/", data=None, format="json"
        )

        self.assertEqual(response.status_code, HTTP_204_NO_CONTENT)
        self.assertEqual(Order.objects.all().count(), 0)

테스트해보기

python manage.py test commerce.tests_commerce.test_order  # 주문 모델만 테스트
python manage.py test  # 전체 테스트

drf-yasg 라이브러리로 Swagger REST API 문서화 (drf-yasg 공식 문서 참고)

# djarf/settings.py
...
INSTALLED_APPS = [
    ...
    "drf_yasg",
]
# djarf/urls.py
...
from drf_yasg import openapi
from drf_yasg.views import get_schema_view

schema_view = get_schema_view(  # REST API의 전반적인 설정
    openapi.Info(
        title="Djarf API",
        default_version="v1",
        description="Django applications with REST framework",
        terms_of_service="https://github.com/panda5176/djarf",
        contact=openapi.Contact(email="panda5176@gmail.com"),
        license=openapi.License(name="MIT License"),
    ),
    public=True,
    permission_classes=[AllowAny],  # 아무나 접근 가능
)
...
urlpatterns = [
    ...
    re_path(  # REST API Json 스키마를 생성
        r"^swagger(?P<format>\.json|\.yaml)$",
        schema_view.without_ui(cache_timeout=0),
        name="schema-json",
    ),
    re_path(  # Swagger 문서를 생성
        r"^swagger/$",
        schema_view.with_ui("swagger", cache_timeout=0),
        name="schema-swagger-ui",
    ),
    re_path(  # Redoc 문서를 생성
        r"^redoc/$",
        schema_view.with_ui("redoc", cache_timeout=0),
        name="schema-redoc",
    ),
]

댓글