테스트 DB없이 Unit Test 하기 in Django

Min-Ho Lee·2020년 10월 29일
7

Learn Django

목록 보기
9/13

Thu_Oct_29
.
.
.
취업 준비를 하면서 여러 회사에 지원하다 보면 과제를 주는 회사들도 있다.
특히 백엔드 개발자들은 AWS EC2 배포나 Unit Test를 하면 가산점을 얻기도 한다.
처음에는 Unit Test를 로컬에서 진행하면서 API가 잘 돌아가는지 안돌아가는지 확인이 가능하다.

그런데 문제는 Django의 settings.py에서 DB 세팅을 AWS의 RDS로 지정하면 유닛테스트가 안된다는 것이다.

우리가 보통 장고에서 유닛테스트를 실행하면 장고에서는 테스트 DB를 만들어서 테스트를 진행한다고 한다.

그래서 보통 setup부분에 테스트 DB에서 실험할 데이터들을 create해주고
삭제는 teardown에서 해준다.

그런데 나는 RDS에 있는 DB의 데이터를 가지고 직접 Unit Test를 하고싶었다.

.
├── README.md
├── config
├── manage.py

먼저 장고에서 프로젝트를 생성하면 manage.py와 프로젝트의 세팅을 관리하는 config dir이 생성된다.(이름은 다를 수 있음)

프로젝트의 세팅을 관리하는 config안에는 다음과 같이 생겼다.

├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py

settings.py에서 프로젝트에 관한 설정을 다루곤 한다.
나는 지금 settings.py에 DB의 설정을 AWS RDS로 세팅 해놓은 상태이다.

예를들어 movie 라는 앱을 만들었다고 해보자.

보통 앱을 만들면 test.py라는 파일이 존재하는데 여기서 유닛테스트 관련 로직을 짜고
다시 manage.py가 있는 상위 폴더로 올라와 python manage.py test movie라는 명령어로
실행을 한다.

그런데 DB 세팅을 RDS로 해놓고 test를 돌리면 에러가 난다.

그리고 중요한 점이 우리는 RDS의 DB로 test를 하고싶지만 장고는 계속해서 테스트 DB를 만들어 test를 하려고 하는 것이다.

test를 실행하면 다음과 같은 문장이 나오는데 이것이 테스트 DB를 이용해 test를 한다는 것이다.

Creating test database for alias 'default'...

🤔 그렇다면 어떻게 바꿔줘야 할까?

일단 테스트 DB의 생성을 막아주기 위해 config 디렉토리 안에 다음 두 파일을 추가 해준다.

├── config
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── settings_test.py # 추가
│   ├── test_runner.py # 추가
│   ├── urls.py
│   └── wsgi.py

settings_test.py 라는 파일과 test_runner.py라는 파일을 추가해줬다.

일단 두 파일을 쉽게 설명하자면

test_runner.py

는 테스트 DB를 만들지 않고 내가 설정한 DB로 테스트를 할 수 있게 해주는 것이다.

settings_test.py

는 내가 프로젝트 설정을 한 기본 settings.py의 모든 내용을 가져온 후, 테스트를 test_runner.py라고 알려주는 파일이다.

그리고 우리는 test를 할 때,
python manage.py test movie 가 아닌,
python manage.py test movie --settings='config.settings_test' 라고 실행을 하여
최종적으로 우리가 설정해준 settings_test라는 세팅 값으로 테스트를 해 줄 것이다.

두 파일의 내용은 다음과 같다.

test_runner.py

from django.test.runner import DiscoverRunner

class TestRunner(DiscoverRunner):

    def setup_databases(self, **kwargs):
        pass

    def teardown_databases(self, old_config, **kwargs):
        pass

여기서 teardown_databases 함수의 파라미터로 꼭 old_config를 추가해야 되는 것을 잊지 말자.

이 파일에는 장고 유닛테스트에서 사용되는 runner 를 재정의하는 클래스인 TestRunner를 정의한다.
TestRunner 클래스가 상속받는 DiscoverRunner 클래스가 바로 테스트 DB 를 생성을 담당하는 클래스이다.

새롭게 정의한 TestRunner 에서 위의 세 메서드를 재정의하여 비어두면, 테스트 시 테스트 DB 의 생성이 없어도 테스트가 가능해진다.

settings_test.py

from config.settings import *

TEST_RUNNER = 'config.test_runner.TestRunner'

이 파일은 settings.py 의 모든 항목을 가져옴과 동시에, testrunner.py 파일에서 정의한 TestRunner 클래스를 테스트 러너로 지정하는 파일이다.

이렇게 하면 모든 준비가 끝났다.

아까 언급한대로 python manage.py test movie --settings='config.settings_test'라는 명령어로 테스트를 해주면 된다.

python manage.py test movie --settings='config.settings_test'

System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.377s

OK

그러면 이렇게 테스트가 잘 진행이 된다.

그리고 위에서 말했듯
Creating test database for alias 'default'...
라는 문구가 보이지 않는다.

우리가 test_runner.py에서 테스트 DB를 생성하지 않도록 재정의 해주었기 때문이다.

글을 적으면서 느낀 건데 이렇게 테스트를 진행해 주면 로컬에 있는 DB의 데이터로도 테스트가 충분히 가능할 것이다.

요즘 unit test에 대해서 더 공부해보고 싶었는데 좋은 자료를 준 태성님 감사합니다 ❤️ 🙏

참고 자료
링크1
링크2

ps. 참고로 DiscoverRunner 클래스를 상속받았었는데, 원래는 이 클래스가 아니었다.
그런데 얼마 전부터 업데이트가 되어 DiscoverRunner로 바뀌었다고 하니 믿고 써도 된다!

ps2. 우리는 세팅 값을 바꿔준 settings_test로 테스트하기 위해 위의 명령어를 사용했지만, settings가 아닌 testrunner로 test를 돌릴 수도 있다.
python manage.py test movie --testrunner='config.test_runner.TestRunner'
로 말이다.

진짜 끝!

profile
🐇 Rabbit can take a rest, but 🐢 turtle can't

1개의 댓글