티스토리 뷰
728x90
반응형
테스트 코드를 작성할 때 BaseTestCase 클래스를 별도로 작성하면 테스트 코드를 더 간편하게 관리할 수 있다.
예를 들어, setUp 메서드를 통해 초기 데이터를 생성하고, 여러 테스트에서 별도의 추가 작성 없이 재사용하는 것이다.
하지만 SimpleUploadedFile 사용한다면 이미지 포스팅 테스트를 작성할 때 다음과 같은 문제가 발생할 수 있다.
- BaseTestCase 클래스에서 setUp 메서드를 통해 이미지와 함께 게시글(Post)을 생성하고, 이를 PostTest 클래스의 테스트 메서드에서 재사용하려고 할 때, 새로운 포스팅 요청이 실패하며 에러가 발생한다.
# response.data
{'image': [ErrorDetail(string='제출한 파일이 비어있습니다.', code='empty')]}
문제의 원인
이 에러는 SimpleUploadedFile 객체가 한 번 읽으면 파일 포인터가 끝으로 이동하기 때문에 발생한다.
파일 포인터가 끝에 위치한 상태에서는 이미지 데이터를 다시 읽을 수 없기 때문에 파일이 비어있다고 판단하게 된다.
그렇기 때문에 재요청 시에 empty 에러가 발생하는 것이다.
해결 방법
이 문제를 해결할 수 있는 방법 세 가지를 소개하려고 한다.
- 파일 포인터를 초기화(seek(0)) 하여 객체를 재사용.
- 새로운 SimpleUploadedFile 객체 생성.
- 각 테스트 클래스에서 독립적으로 객체 생성.
1. 파일 포인터 초기화
- SimpleUploadedFile 객체를 재사용하기 위해서 파일 포인터를 맨 처음 위치로 돌려놓는 방법이 있다.
- seek(0) 메서드를 사용하면 초기화가 가능하다.
- 초기화를 한다면 동일한 객체를 여러번 사용할 수 있다.
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from rest_framework.test import APIClient
class BaseTestCase(TestCase):
def setUp(self):
self.client = APIClient()
self.image = SimpleUploadedFile("test_image.jpg", b"image_content", content_type="image/jpeg")
# 첫 번째 포스팅 생성
self.client.post(
"/posts/create/",
{"title": "First Post", "content": "This is the first post.", "image": self.image},
format="multipart"
)
class PostTest(BaseTestCase):
def test_create_post(self):
# 파일 포인터 초기화
self.image.seek(0)
# 두 번째 포스팅 생성 (이미지 재사용)
response = self.client.post(
"/posts/create/",
{"title": "Second Post", "content": "This is the second post.", "image": self.image},
format="multipart"
)
self.assertEqual(response.status_code, 201)
2. 새로운 SimpleUploadedFile 객체 생성하기
- 이미지를 요청할때마다 새로운 SimpleUploadedFile 객체를 생성하여 사용한다.
- 새롭게 생성함으로써 파일 포인터 문제를 관리할 필요가 없어진다.
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from rest_framework.test import APIClient
class BaseTestCase(TestCase):
def setUp(self):
self.client = APIClient()
image = SimpleUploadedFile("test_image.jpg", b"image_content", content_type="image/jpeg")
# 첫 번째 포스팅 생성
self.client.post(
"/posts/create/",
{"title": "First Post", "content": "This is the first post.", "image": image},
format="multipart"
)
class PostTest(BaseTestCase):
def test_create_post(self):
# 새 이미지 생성
new_image = SimpleUploadedFile("test_image.jpg", b"image_content", content_type="image/jpeg")
# 두 번째 포스팅 생성 (이미지 재사용)
response = self.client.post(
"/posts/create/",
{"title": "Second Post", "content": "This is the second post.", "image": new_image},
format="multipart"
)
self.assertEqual(response.status_code, 201)
3. 테스트 클래스별로 setUp 메서드 정의
- 클래스마다 필요시에 독립적으로 setUp 메서드를 추가 작성하여 SimpleUploadedFile 객체를 생성한다.
- 테스트마다 새롭게 객체가 생성됨으로 파일 포인터 문제를 회피할 수 있다.
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from rest_framework.test import APIClient
class BaseTestCase(TestCase):
def setUp(self):
self.client = APIClient()
image = SimpleUploadedFile("test_image.jpg", b"image_content", content_type="image/jpeg")
# 첫 번째 포스팅 생성
self.client.post(
"/posts/create/",
{"title": "First Post", "content": "This is the first post.", "image": image},
format="multipart"
)
class PostTest(BaseTestCase):
def setUp(self):
super().setUp()
self.image = SimpleUploadedFile("test_image.jpg", b"image_content", content_type="image/jpeg")
def test_create_post(self):
# 두 번째 포스팅 생성 (이미지 재사용)
response = self.client.post(
"/posts/create/",
{"title": "Second Post", "content": "This is the second post.", "image": self.image},
format="multipart"
)
self.assertEqual(response.status_code, 201)
728x90
반응형
댓글