과거에 API를 작성한 후 테스트 할때 Insomnia 를 사용하여 직접 요청에 대한 응답 값을 확인했었다.
물론 Insomnia 를 사용해서 API를 테스트 하는 방법도 나쁘지 않았지만 관리 하는 API가 많아지고 복잡한 기능의 API를 테스트 하다 보니 관리가 힘들어지고 API를 테스트 하는데 걸리는 시간도 늘어나게 되었다.
Django의 테스트 프레임워크를 사용하면 자동화된 방식으로 다양한 테스트를 작성하고 실행할 수 있다. Django는 API에 대한 테스트도 지원합니다. 이를 통해 코드가 변경되더라도 새로운 버그를 빠르게 찾을 수 있다.
앱 디렉토리 안에 tests.py 파일을 만들어 테스트를 작성할 수 있다. 하지만 더 구조화된 테스트를 원한다면, tests라는 디렉토리를 만들고 그 안에 각 기능별로 테스트 파일을 나눠 관리할 수 있다.
간단한 구조
myapp/
tests.py
복잡한 구조
tests/
__init__.py
test_models.py
test_views.py
test_api.py
이렇게 구조화하면 앱 내의 각 기능에 대해 별도의 테스트 파일을 관리할 수 있어 가독성과 유지 보수에 좋다.
테스트 코드는 Django의 TestCase를 상속받아 작성할 수 있습니다. TestCase는 Django에서 확장한 테스트 클래스이며, 자동으로 데이터베이스를 초기화해주고 롤백 기능을 제공한다.
각 테스트 함수의 네이밍은 test 로 시작 해야 한다.
from django.test import TestCase
from myapp.models import MyModel
class MyModelTest(TestCase):
"""MyModel Test Definition"""
def test_model_creation(self):
"""test model create"""
name = "Test object"
# 모델 객체 생성
obj = MyModel.objects.create(name=name)
# 객체가 정상적으로 생성되었는지 테스트
self.assertEqual(obj.name, name)
이처럼 간단한 테스트를 진행 할 수 있다.
TestCase의 setUp() 메서드를 사용하여 각 테스트 전에 실행될 코드를 정의할 수 있다. 예를 들어, 공통으로 사용할 테스트 데이터를 미리 생성해둘 수 있다.
from django.test import TestCase
from myapp.models import MyModel
class MyModelTest(TestCase):
def setUp(self):
# 테스트 실행 전 데이터베이스에 미리 객체를 생성
self.obj = MyModel.objects.create(name="Set up object")
def test_model_setup(self):
# setUp에서 생성한 객체가 있는지 확인
self.assertEqual(self.obj.name, "Set up object")
setUp() 메서드를 사용하면 각 테스트 전에 기본 설정을 통해 반복적인 객체 생성을 줄일 수 있다.
API 테스트를 위한 초기 데이터 세팅을 주로 진행한다.
DRF를 사용하여 API를 개발하면 APITestCase를 활용해 API 테스트를 할 수 있다. API 테스트에서는 GET, POST, PUT, DELETE 등의 요청을 테스트 할 수 있다.
from rest_framework import viewsets
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
# serializers.py
from rest_framework import serializers
from myapp.models import MyModel
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from myapp import views
router = DefaultRouter()
router.register(r'mymodel', views.MyModelViewSet, basename='my_model')
urlpatterns = [
path('', include(router.urls)),
]
API 엔드포인트:
/mymodel/ → MyModel 객체 목록을 가져오거나 새 객체를 생성/mymodel/pk/ → 특정 MyModel 객체에 대한 상세 정보, 수정, 삭제URL 사용:
reverse('my_model_list'): "/mymodel/" URL을 생성하며, GET 요청 시 객체 목록을 가져오고 POST 요청 시 객체를 생성reverse('my_model_detail', kwargs={'pk': self.my_model.pk}): /mymodel/<pk>/ URL을 생성하며, 특정 객체에 대해 GET, PUT, DELETE 요청을 수행from rest_framework.test import APITestCase
from rest_framework import status
from django.urls import reverse
from myapp.models import MyModel
class MyAPITest(APITestCase):
def setUp(self):
# 테스트 데이터 생성
self.my_model = MyModel.objects.create(name="API Test Object")
# url 정의
self.url = reverse('my_model_detail', kwargs={'pk': self.my_model.pk})
def test_get_api(self):
# GET 요청을 테스트
response = self.client.get(self.url)
# 상태 코드 확인
self.assertEqual(response.status_code, status.HTTP_200_OK)
# 응답 데이터 확인
self.assertEqual(response.data['name'], 'API Test Object')
def test_post_api(self):
# POST 요청을 테스트
data = {'name': 'New Object'}
response = self.client.post(reverse('my_model_list'), data)
# 상태 코드 확인
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
# 새 객체가 제대로 생성되었는지 확인
self.assertEqual(MyModel.objects.count(), 2)
self.assertEqual(MyModel.objects.last().name, 'New Object')
위와 같은 방법으로 API 테스트 코드를 작성 할 수 있다.
위의 예시 외에 더 다양한 형식으로 API 테스트 코드를 작성 할 수 있다.
작성한 API에 대한 여러가지 성공과 실패에 대한 케이스를 작성하면 이후 변경 사항이 생겼을 때 기존의 로직이 잘 동작하는지 검사하기 좋다.