파이썬 장고가 제공하는 단위 테스트는 코드 배포전에 에러를 검출해 볼 수 있는 방법으로 무척 유용합니다. 젠킨스 빌드시에도 활용하여 자칫 로컬 환경과 원격 빌드/운영 환경의 차이에도 대응할 수 있어 장애를 막는 지름길이 되기도 합니다.
파이썬 장고의 단위 테스트를 구성해서 잘 사용하던 중, 갑자기 (원인은 알 수 없습니다 ㅜㅜ) TransactionManagementError와 함께 테스트가 지속적으로 실패하기 시작하여 열심히 구글링하고 삽질한 내용을 간략히 정리해 봅니다.
장고 단위 테스트를 사용하기 위해서는 아래와 같은 코드를 만들게 됩니다. 참고로 코드는 장고 공식 문서에서 가져왔습니다. 이때, 실제 테스트를 수행하는 클래스는 매개변수로 TestCase 클래스의 인스턴스를 받게 됩니다. 아래의 코드에서는 TestCase 클래스를 가져왔네요.
import unittest
from django.test import Client
class SimpleTest(unittest.TestCase):
def setUp(self):
# Every test needs a client.
self.client = Client()
def test_details(self):
# Issue a GET request.
response = self.client.get('/customer/details/')
# Check that the response is 200 OK.
self.assertEqual(response.status_code, 200)
# Check that the rendered context contains 5 customers.
self.assertEqual(len(response.context['customers']), 5)
코드를 보면 실제 테스트 함수들이 클래스 내에 기술이 되어 있습니다. 제 경우 문제는 테스트 함수들이 데이터베이스에 대한 질의를 수행하는 코드를 호출하면서 발생했습니다. 일반적인 TestCase의 서브 클래스로는 데이터베이스 관련 코드를 수행하고 테스트 결과를 돌려주는데 문제가 있었습니다. 테스트가 수행되면서 발생한 에러는 아래와 같습니다.
raise TransactionManagementError(
django.db.transaction.TransactionManagementError: An error occurred in the current transaction. You can't execute queries until the end of the 'atomic' block.
이 에러 메세지가 참 얄미운게 내용이 좀 뭉뚱그려져 있습니다. 굉장히 명확한 에러이기 때문에 TestCase 클래스를 트랜잭션을 지원하는 것으로 변경하라고 하면 되었을 것을 저렇게 표현하고 있어서 애를 먹게 만들더군요. 이 문제에 대한 첫번째 접근은 장고 공식문서에서 가이드하는 TransactionTestCase 클래스의 사용입니다.
제 경우는 장고 REST Framework 를 사용하고 있던 관계로 이쪽에서 필요한 클래스의 변경 작업을 진행했습니다. 기존에 에러가 발생하던 테스트 코드에서는 REST Framework가 제공하는 test 패키지의 APITestCase 클래스를 쓰고 있었습니다. 이 클래스를 APITransactionTestCase로 변경하니 에러가 말끔히 사라지고 테스트도 정상적으로 수행되기 시작했습니다.
# 기존
from rest_framework.test import APITestCase
# 변경
from rest_framework.test import APITransactionTestCase
TransactionManagementError로 검색을 하다보면 여러가지 문제 상황과 이에 대한 대처법들이 소개되고 있습니다. 가령 1) 테스트 테이블에 데이터를 피딩하는 과정에 문제였고 이를 수정하여 해결 했다는 분도 계셨고, 2) 테스트가 수행하는 코드 내에 try~except 구문이 사용되는 경우 transaction.atomic() 을 이용해서 코드를 변경해야 된다는 글도 있었습니다.
다양한 트러블슈팅 사례와 방법이 있는 것을 보면 에러 메세지가 조금 더 친절하게 출력되면서 원인을 빠르게 확인할 수 있었으면 어땠을까 하는 생각이 듭니다. 그래도 트러블슈팅을 하면서 또 파이썬에 대해, 장고에 대해 조금 더 알 수 있었기에 의미 없는 시간은 아니었던 것 같습니다!
파이썬과 관련하여 최근에 겪었던 다른 이슈들과 해결 방법은 아래의 글을 참고해 보시기 바랍니다!