All Articles

pytest-django TEST DB setup

1. Test DB 생성 (django default) 및 이용

  • settings.DATABASES config 활용
  • test_ DB schema 생성
  • django models 바탕으로 DB 생성
  • Test data:

    • 비어 있는 TEST DB 에 실행하기 원하는 데이터를 채워넣어줘야 한다.
    • models.py 에서 User import
    • User.objects.create(id=1, name=“유저”, age=30)
  • 장점:

    • Schema 변경시 피드백이 빠름
  • 단점:

    • 테스트 데이터 생성 코드를 짜야 한다.

      • 값이 중요하지 않다면, model_bakery 사용
    • Read Only DB 미지원 (managed = False)
    • Multi DB 미지원

      • 모든 app의 models를 하나의 DB 로 몰아 넣는다.

2. TEST DB 생성 및 SQL DUMP 실행

# conftest.py
import subprocess
import pytest
from django.db import connections
import pymysql

# user는 host에 접속할수 있고, db create 권한이 있어야 한다.
TEST_DB = {
    "base": {
        "host": "localhost",
        "user": "test_user",
        "password": "test_pw",
        "charset": "utf8mb4"
    },
    "default": {
        "name": "testtest_default",
    },
    "multidb1":{
        "name": "testtest_multi1"
    }
}

# SQL 실행을 위한 function
def run_sql(sql):
    conn = pymysql.connect(**TEST_DB["base"])
    cur = conn.cursor()
    cur.execute(sql)
    conn.close()

# SQL dump load를 위한 func 
# `mysql --user=test_user --password=test_pw < SQL.dump` 실행
def load_mysql_dump(filepath, user, passwd, db_name):
    with open(filepath, 'r') as f:
        command = ['mysql', f'--user={user}', f'--password={passwd}', db_name]
        proc = subprocess.Popen(command, stdin=f)
        _, stderr = proc.communicate()
        if stderr:
            print(repr(stderr))


@pytest.fixture(scope='session')
def django_db_setup():
    from django.conf import settings
    # 기존 연결 되던 DB 변경
    settings.DATABASES['default']['NAME'] = TEST_DB["defualt"]["name"]
    settings.DATABASES['multidb1']['NAME'] = TEST_DB["multidb1"]["name"]

    # Test DB 생성
    run_sql(f"""DROP DATABASE IF EXISTS `{TEST_DB["defualt"]["name"]}`;""")
    run_sql(f""" CREATE DATABASE {TEST_DB["defualt"]["name"]};""")
    run_sql(f"""DROP DATABASE IF EXISTS `{TEST_DB["multidb1"]["name"]}`;""")
    run_sql(f""" CREATE DATABASE {TEST_DB["multidb1"]["name"]};""")

    # Test DB load dump data
    conf = TEST_DB["base"]
    load_mysql_dump("default_dump.sql", conf["user"], conf["password"], TEST_DB["defualt"]["name"])
    load_mysql_dump("multidb1_dump.sql", conf["user"], conf["password"], TEST_DB["multidb1"]["name"])

    # 테스트 종료까지 yield, 테스트 종료시 실행된다.
    yield

    #테스트 종료후 Test DB Drop, 주석 처리 해놓을 경우 DB 가 계속 잔존
    run_sql(f""" DROP DATABASE {TEST_DB["defualt"]["name"]};""")
    run_sql(f""" DROP DATABASE {TEST_DB["multidb1"]["name"]};""")

    for connection in connections.all():
        connection.close()
  • 원하는 형태로 TEST DB를 손쉽게 불러올 수 있다.
  • Test data:

    • 내가 원하는 형태와 data를 가지고 있는 DB를 dump 하면 끝
  • 장점:

    • DB 자체를 freeze 한 채로 사용할 수 있다.(schema 변동이 없는 고정된 케이스라면 이걸로도 충분)
    • 멀티 DB 사용 가능하다.
    • Read Only DB 데이터 입력이 가능하다.
  • 단점:

    • 데이터, schema 변화대응 느림,
    • 해당 SQL 을 실행해서 DB를 만들고, 값 수정, 다시 dump를 해야한다.

3. 기존 DB 이용

#conftest.py

new_default =  {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'prepaired_test_db',  # DB명
        'USER': 'test_user',  # 데이터베이스 계정
        'PASSWORD': 'test_pw'  # 계정 비밀번호
        'HOST': 'db.example.com',  # 데이테베이스 주소(IP)
        'PORT': '3306',  # 데이터베이스 포트(보통은 3306)
        'OPTIONS': {
            'charset': 'utf8mb4',
        }
    }

@pytest.fixture(scope='session')
def django_db_setup():
    from django.conf import settings
    
    # 접속 정보를 내가 원하는 것으로 덮어 씌운다.
    settings.DATABASES['default'] = new_default
    

미리 설정해 놓은 TEST DB 에 접속, 저장 되어 있는 DB data를 사용

  • Test data:

    • DB에 저장된 데이터
  • 장점 :

    • 공통 테스트 DB 공유
  • 단점 :

    • DB가 각 Test 시행에 대해서 비독립
    • 테스트가 데이터 변조, 타 테스트에 영향을 끼칠 수 있다.

4. Django loaddata

# conftest.py

import pytest

from django.core.management import call_command

@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
    with django_db_blocker.unblock():
        call_command('loaddata', 'my_fixture.json')

Django 제공, dumpdata 로 data 백업, 저장된 data load.

  • 장점:

    • SQL 변환등을 거칠 필요가 없이 단순하다.
  • 단점:

    • DB 가 단순할 경우 잘 되지만 아닐 경우 SQL dump가 낫다.
    • Multi DB 미지원