Django & DRF에서 테스트 진행하기

Category
Published
August 13, 2024
Last updated
Last updated October 25, 2024
💡
이 포스트는 현재 작성중입니다

개요

Python(파이썬)의 웹 프레임워크인 Django(장고)와 Django Rest Framework(DRF)에서 테스트를 환경을 구성하고, 좋은 테스트를 작성하는 방법을 정리해보았습니다.

테스트 환경 구성

테스트 폴더 분리

기본적으로 장고에서는 앱마다 tests.py 파일이 제공됩니다. 하지만 다양한 기능이 추가되고 앱이 무거워지면 테스트가 많아지고 테스트 파일 분리의 필요성이 느낄 수 있습니다.
이럴 때는 앱에 tests/ 폴더를 추가해주고, 테스트 파일들을 test~.py 의 형식으로 만들어주면 됩니다.
💡
test~.py 형식으로 이름을 지정하는 이유는, 테스트 파일을 인식할 때 기본적으로 test~.py 형식의 파일을 테스트 파일로 인식하기 때문입니다.
이때 주의할 점으로는 tests/ 폴더에 __init__.py 파일(빈 파일도 OK)을 추가해줘야 파이썬이 해당 디렉토리를 패키지로 인식해 테스트를 탐색할 수 있습니다.
다음은 파일 구조의 예시입니다.
myproject/ ├── manage.py ├── myproject/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── myapp/ ├── __init__.py ├── models.py ├── views.py └── tests/ ├── __init__.py ├── test_models.py ├── test_views.py └── test_e2e.py

테스트 환경 분리

장고에서 개발/배포 환경에서 실행되는 데이터베이스나 다른 설정들을 테스트 환경에서는 사용하고 싶지 않을 수 있습니다. 이를 위해 다음과 같은 방법으로 테스트 환경을 분리할 수 있습니다.

1. 테스트 실행시 if 분기처리 하기

# 테스트 시 인메모리 sqlite3 DB를 사용하는 예시 if "test" in sys.argv: DATABASES = { "default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"} }
다음과 같이 실행하는 명령 python manage.py test 실행시에 test가 포함되어 있다는 것을 이용해 test 실행시에 설정을 덮어쓸 수 있습니다.
다만 해당 방식은 python manage.py test가 아닌 별도로 테스트를 실행할 때에는 테스트 환경임을 인식할 수 없는 문제가 있습니다.

2. settings.py 파일 분리하기

장고에서는 환경 분리시에 settings.py 파일을 분리하는 방법을 주로 사용합니다.
다음은 settings.py 파일 분리의 예시입니다.
myproject/ ├── manage.py └── myproject/ ├── __init__.py ├── settings/ │ ├── __init__.py │ ├── base.py │ ├── dev.py │ ├── test.py │ └── prod.py ├── urls.py └── wsgi.py
이렇게 설정 후 테스트시에 매번 python manage.py test --settings=myproject.settings.test 와 같이 사용할 수도 있지만, 앞서 설명한 명령어에 test가 포함되어 있는지 확인하는 방법을 통해 settings/test.py 를 사용하게 할 수도 있습니다.
import os import sys def main(): if "test" in sys.argv: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.test") else: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.dev")
manage.py

3. .env 환경변수 파일 분리

또는 환경변수를 .env, .env.production, .env.production.local 등의 파일로 구분하는 방법을 사용할 수도 있습니다.

4. 테스트시 설정, 환경변수 변경해주기

 
위의 방법들은 병용할 수 있습니다.

Django TestRunner

테스트 실행 방법

장고 기본 테스트

장고에서 테스트를 실행하는 경우에 일반적으로 장고의 기본 테스트 실행 방식을 사용할 수 있습니다.
python manage.py test python manage.py test <app_name> # 특정 앱의 테스트만 실행
 
또는 VSCode로 개발을 한다면, 추가적으로 VSCode에서 제공하는 테스팅 UI를 사용할 수 있습니다.

VSCode 테스트(django test)

 

VSCode 테스트(unittest, 비권장)

💡
다음 내용은 VSCode제공 장고 test가 아닌 일반 unittest 방식으로 장고 테스트를 실행하는 방법입니다.
VSCode는 파이썬에서 unittest와 pytest와의 연동을 기본적으로 지원합니다.
VSCode 테스트 환경은 모두 개별적으로 설정으로 지정해줄 수도 있지만, 프로젝트 별로 설정을 별도로 관리하고 협업시에 같은 환경을 공유하기 위해 .vscode/settings.json 파일을 이용해 개별적으로 설정해주는 것을 권장합니다.
{ "python.testing.pytestEnabled": false, "python.testing.unittestEnabled": true, "python.testing.unittestArgs": ["-v", "-s", ".", "-p", "test*.py"] }
.vscode/settings.json
위와 같이 설정한다면 unittest를 사용하고, 경로에 있는 파일중 test~.py 파일들을 탐색합니다. 이렇게 찾은 테스트들은 VSCode 좌측의 Testing 섹션에서 찾아볼 수 있습니다.
좌측 하단 비커 모양의 Testing 섹션
좌측 하단 비커 모양의 Testing 섹션

DJANGO_SETTINGS_MODULE 환경 변수 설정

manage.py를 보면 settings.py의 위치를 알려주기 위해 환경변수를 설정해주는 부분이 있습니다.
#!/usr/bin/env python """Django's command-line utility for administrative tasks.""" import os import sys def main(): """Run administrative tasks.""" # manage.py에는 아래와 같이 settings.py 파일을 알려주는 환경변수를 설정해주는 부분이 있다. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") ~~~ if __name__ == "__main__": main()
VSCode를 이용해 unittest를 작동시켰을 때, 해당 방식은 manage.py 파일을 이용하는 방식이 아니기 때문에 DJANGO_SETTINGS_MODULE 환경변수가 기본적으로 설정되지 않습니다. 그렇기 때문에 각 tests/ 폴더의 __init__.py에 다음과 같이 환경변수를 설정해주어야 합니다.
import os from django import setup os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") setup()
myapp/tests/__init__.py
이때 테스트용 settings.py를 분리했다면 DJANGO_SETTINGS_MODULE"config.settings.test" 과 같이 설정해줌으로써 테스트시에 테스트용 settings.py 파일을 사용할 수도 있습니다.

환경변수 파일 설정

이때 테스트용 env 파일을 설정해줄 수 있습니다. 다만 vscode를 통해 실행하는 파이썬 코드에 대해 모두 적용이 되니, 테스트외에 vscode로 실행을 한다면 문제가 될 수 있습니다.
{ "python.envFile": "${workspaceFolder}/.env.test" }
.vscode/settings.py

__init__.py 환경변수 설정

 
또는 DJANGO_SETTINGS_MODULE을 설정해주었을 때 처럼 테스트 폴더의 __init__.py에서 환경변수를 지정해줄 수 있습니다.
import os from django import setup os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings") os.environ.setdefault("ENVIRONMENT", "test") # 다음과 같이 환경변수 추가 setup()

ALLOWED_HOSTS testserver 설정

ALLOWED_HOSTS = env.get("DJANGO_ALLOWED_HOSTS", "").split(" ") + ["testserver"]
settings.py

테스트에서 인메모리 파일 스토리지 사용하기

Django 4.2부터 django.core.files.storage.InMemoryStorage가 추가되었습니다.
@override_settings(DEFAULT_FILE_STORAGE="django.core.files.storage.InMemoryStorage") class SimpleTestCase(APITestCase): def storage_related_test(self): ~~~
위와 같이 사용하면 실제 파일 시스템 스토리지나 사용하고 있는 스토리지에 영향을 미치지 않고 빠르게 테스트를 실행할 수 있습니다.

가짜 이미지 파일 사용하기

이미지 생성 없이 base64와 SimpleUploadedFile를 이용하여 빠르게 이미지가 필요한 테스트를 진행할 수 있습니다.
def test_image_something(self): # 테스트 이미지 생성 image_content = base64.b64decode( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==" ) uploaded_file = SimpleUploadedFile( "test_thumbnail.png", image_content, content_type="image/png" ) response = self.client.post( reverse("image_api", {"image": uploaded_file}, format="multipart") )

Unittest

Mock