본문 바로가기

개발/파이썬

Django에서 Replica DB가 있을 때의 테스트 코드 문제 해결하기

반응형

Django에서 ReplicaDB (ReadonlyDB)가 있을 때 테스트 코드를 작성하면 다음과 같은 문제가 발생할 수 있습니다. 분명 데이터베이스 쓰기에 성공했는데, 해당 데이터를 읽어보면 데이터가 없는 경우가 있습니다. 데이터를 default DB에 입력했는데, 읽는 것은 readonly DB에서 읽으려고 해서 해당 문제가 발생합니다. 테스트 코드를 작성하는 상황에서는 보통 로컬에서 DB를 생성하기 때문에 replica DB를 따로 사용하지 않을 가능성이 크기 때문입니다.

Django의 공식문서를 확인하면 replicaDB에 대해서는 MIRROR를 defaultDB로 설정하여 replica DB에 대해서 DB생성을 막는 방법을 알려줍니다.

아래는 Django 공식문서의 예제입니다.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'HOST': 'dbprimary',
         # ... plus some other settings
    },
    'replica': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'HOST': 'dbreplica',
        'TEST': {
            'MIRROR': 'default',
        },
        # ... plus some other settings
    }
}

하지만, 이렇게 해도 replica DB가 생성되지 않을 뿐, 여전한 문제가 발생했습니다. (만약 이렇게 해서 해결된다면 다음 내용은 지나치셔도 됩니다.) 몇 시간 삽질을 해보니 해당 문제는 아주 오래된 Django의 이슈임을 확인했습니다.

해당문제는 여전히 connections["replica"]가 replica DB에 접근하려고 해서 생기는 문제입니다. 이는 Django의 테스트케이스를 오버라이딩해서 해결할 수 있습니다.

# utils/test.py

from django.test import TestCase

class BaseTestCase(TestCase):

    databases = ["default", "replica"]

    @classmethod
    def setUpClass(cls):
        connections["replica"]._orig_cursor = connections["replica"].cursor
        connections["replica"].cursor = connections["default"].cursor
        super().setUpClass()

    @classmethod
    def tearDownClass(cls):
        connections["replica"].cursor = connections["replica"]._orig_cursor
        super().tearDownClass()
  • 테스트케이스를 시작하기 전에 replica의 cursor를 default의 cursor로 바꿔줍니다.
  • 테스트케이스가 끝나면 다시 replica의 cursor를 원래대로 돌려줍니다.
  • Django 2.2부터 Multiple Database (Replica DB 포함)를 쓸 때는 databases = "__all__" 또는 관련 있는 데이터베이스들을 모두 명시해 주어야 합니다. (databases = ["default", "replica"])

이제 해당 클래스를 대신 import해서 기존의 문제를 해결할 수 있습니다.

# someapp/test.py

from utils.test import BaseTestCase

class SomeTestCase(BaseTestCase):
    """

    ...
    Test code goes here
    ...

    """
반응형