잠깐 방치해 두었던 장고로 제작된 서비스의 테스트를 개선해야 할 필요성을 느꼈습니다.
개선이 필요한 사항은
1. ci. 커밋 시 자동으로 테스트를 진행이 필요
2. 테스트 시 api를 이용한 특정 작업이 자동으로 실행되는데, 이를 막기
3. 이미지 업로드 시 사용하는 S3을 실제 production bucket에 올라가게 해 두었는데, 이를 막기
커밋 시 자동 테스팅
우선 기존에 release 브랜치에 push시, Github Action을 이용하여 자동으로 실제 배포 서버의 워커를 실행시켜 자동으로 배포되도록 설정해 두었습니다. 이를 활용하여 Github Action을 다시 활용해 자동 테스트를 진행하도록 만들었습니다.
name: Test app
concurrency:
group: production
cancel-in-progress: true
on:
push:
branches: [master]
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11"]
steps:
- uses: actions/checkout@v3
- name: Copy env file
run: cp example.env .env
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
pip install -r requirements.txt
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Run django test
run: |
python manage.py test
.github/workflows/test.yml을 위와 같이 추가해 주었고, 잘 적용되었습니다.
작업하며 든 생각은, 앞으로 프로젝트를 진행할 때에도 환경변수 분리, ci/cd, 테스트, 로깅은 미리 설정해 두고 작업을 해야겠다 생각했습니다.
테스트 시 api 작동 막기
api가 자동으로 작동되는 것은 signal을 통해 모델 저장 시에 자동으로 실행되는 부분이었는데요, 해당 부분을 작업하며 모델 부분과 서비스 부분을 나눠야 할 필요성을 느꼈습니다.
아무튼 문제를 어떻게 해결할지 생각해 보아야 했는데요, 유닛 테스트라면 잘 분해해서 해당 시그널 부분도 테스트할 수 있었겠지만, 대부분의 테스트를 e2e로 짜둔 시점에서 우선 api와의 연결성을 끊기로 결정했습니다.
이를 위해 signal을 테스트 시 비활성화해 주는 방식을 사용했습니다.
class Tests(APITestCase):
def setUp(self):
post_save.disconnect(
func_name1, sender="model.Model1"
)
post_save.disconnect(
func_name2, sender="models.Model2"
)
위와 같은 방식으로 setUp을 해줌으로써 signal을 테스트 시 비활성화할 수 있습니다.
이때까지는 api가 대부분 단순해 e2e로 테스트하는 게 효율적이라 생각했는데, 이 정도로만 복잡해지더라도 각 부분을 분리하여 각각 테스트해줘야 할 것 같은 필요성을 느꼈습니다.
S3 업로드 막기
S3 이미지 버킷용으로 boto3를 사용하고 있었는데, 검색하며 나온 것은 moto라는 boto3의 Mock을 제공하는 라이브러리였습니다. 해당 라이브러리를 이용해서 시도해 보았습니다.
다만 moto는 유닛 테스트라면 아주 유용했겠지만, 제가 하고 싶은 것은 장고 앱에서 이미지 저장 시 자동으로 올라가는 버킷을 마치 DB를 테스트시에 sqlite로 대체하듯, 자연스럽게 대체하는 것이었기에 이를 구현하기 어려웠습니다.
잠시 시도하며 고민해 보다, 생각해 보니 DEFAULT_FILE_STORAGE 자체를 storages.backends.s3boto3.S3Boto3Storage 에서 기본 파일 스토리지인 django.core.files.storage.FileSystemStorage로 전환하면 되겠다는 꼼수를 생각해 냈습니다.
@override_settings(DEFAULT_FILE_STORAGE="django.core.files.storage.FileSystemStorage")
class Tests(APITestCase):
그리고 @override_settings 데코레이터를 이용해 설정을 변경하여 해결했습니다.
다만 상당히 우회해서 돌아가게만 만든 느낌이기에... 이후에 유닛 테스트를 작성하며 moto를 이용해 볼 예정입니다.
'서버(Server) > 장고 (Django)' 카테고리의 다른 글
Django에 redis 캐싱 적용하기 (0) | 2024.02.09 |
---|---|
장고 필드의 null, blank에 대한 정리 (0) | 2023.08.18 |
[Django Basic] 4. Template (0) | 2023.08.03 |
dj-rest-auth 소셜 로그인(OAuth)에 대하여 (0) | 2023.07.27 |
[Django Basic] 4. View, views.py (0) | 2023.07.27 |