테스트를 할 때 setup 을 통해 사용자 정보나 토큰을 받아오곤 하지만, 이러한 셋업은 테스트가 끝나면 사라질 뿐더러 매 테스트마다 필요한 작업이기 때문에 일일히 적어주긴 조금 번거롭다. 그 때 사용할 수 있는 기능이 SetUpTestData 인데, 이를 사용하면 매번 SetUp 을 적어주지 않아도 테스트 클래스를 실행할 때마다 미리 데이터를 생성해놓는다. 여기서 자세한 사용법을 볼 수 있다.
모질라 문서에서 보면 SetUpTestData 말고도 @classmethod
라는 데코레이터가 있는데, 이는 클래스 인스턴스를 생성하지 않고도 인스턴스 = 클래스명.메서드()
의 형식으로 클래스 메소드를 실행할 수 있게 해주는 기능을 한다. 이때 인스턴스는 위의 한 줄을 통해 생성되었기 때문에 저 코드 뒤로는 인스턴스.메서드()
의 형식으로 써도 그 메서드가 실행된다.
또한 모질라를 보면 알겠지만, @classmethod
아래의 클래스에 들어가는 첫 번째 인자는 self 가 아닌 cls 이다. 본인의 클래스를 다시 호출하는 건데, 본인의 클래스에 대한 인스턴스를 __init__
와 조금 다른 방법으로 생성하고 싶을 때 쓸 수 있다. 예를 들어 __init__
에는 이름과 나이를 인자로 생성하였지만 @classmethod
를 통해 태어난 년도로 생성하고 싶다던가
staticmethod 는 classmethod 와 마찬가지로 인스턴스를 생성하지 않고도 클래스명.메서드()
만으로도 클래스 내의 메서드를 쓸 수 있다. 예를 들어
@staticmethod
def isAdult(age): # self 나 cls 같은 별도의 인자가 없다
return age > 18
이렇게 쓰고 아래에서 print(People.isAdult(22))
를 실행했을 경우, 22는 18보다 크므로 True 를 출력하게 된다.
위와 같은 메서드는 클래스 밖에서 따로 만들어줘도 상관이 없지만, 코드의 깔끔함과 클래스의 유틸성을 이유로 @staticmethod 를 사용해 만들어준 것이다.
class YourTestClass(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user_data = {'username': 'john', 'password' : '1111'}
cls.user = User.objects.create_user('john', '1111')
def setUp(self):
self.access_token = self.client.post(reverse('token_obtain_pair'), self.user_data).data['access']
# .client 가 클래스 메서드가 아니라 토큰 부분은 따로 만들어줘야 한다
위처럼 setUpTestData 를 통해 만들어준 데이터는 테스트를 시작할 때 모든 메서드에 대해 실행된다. 지금은 데이터가 적기 때문에 굳이 setUpTestData 를 사용하지 않아도 괜찮지만, 후에 API 요청이 많아지고 더미데이터의 양이 조금 더 많아졌을 때는 일일히 setUp 을 사용하는 것보다는 setUpTestData 를 통해 먼저 생성해놓고 테스트하는 것이 효율적일 것이다.
파이썬에서 가짜데이터(더미데이터)를 편리하게 생성할 수 있도록 도와주는 모듈이다. 여기서 사용법을 자세히 볼 수 있다.
>>> fake = Faker()
>>> fake
>>> fake.name()
'Jamie Wood'
>>> fake.name()
'Brenda Smith'
>>> fake.name()
'Susan Davis'
faker 는 이름, 주소 외에도 다양한 더미데이터를 생성해줄 뿐더러 옵션을 통해 fake = Faker("ko_KR")
을 통해 한국어 설정 또한 해줄 수 있다.
setUpTestData 를 통해 만들어본 테스트
class ArticleTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user_data = {"email": "hye1029@gmail.com", "password": "1111"}
cls.article_data = {"title": "test title", "content": "test content"}
cls.user = User.objects.create_user("hye1029@gmail.com", "1111")
def setUp(self):
self.access_token = self.client.post(
reverse("token_obtain_pair"), self.user_data
).data[
"access"
] # access 토큰 받아오기 - data['access'] 중요
def test_failed_if_not_logged_in(self):
url = reverse("article-view")
response = self.client.post(url, self.article_data)
self.assertEqual(response.status_code, 403) # 로그인이 안 되었을 시 Forbidden
로그인이 되었을 시 article 작성 테스트
def test_logged_in(self):
response = self.client.post(
path=reverse("article-view"),
data=self.article_data,
HTTP_AUTHORIZATION=f"Bearer {self.access_token}", # header 에 로그인 인증 값 넣기
)
self.assertEqual(response.status_code, 201)
이미지가 있는 article 생성 - 임시 이미지 파일을 생성해 준 뒤 content_type 을 지정하고 인코딩 해주어야 한다.
# 이미지 업로드
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from PIL import Image
import tempfile # 임시 파일
# 임시 파일을 이용해서 임시 이미지 생성
def get_temp_images(temp_file):
size = (200, 200)
color = (255, 0, 0)
image = Image.new("RGBA", size, color)
image.save(temp_file, "png")
return temp_file
def test_create_article_with_image(self):
# 임시 이미지 파일 생성
temp_file = tempfile.NamedTemporaryFile()
temp_file.name = "image.png"
temp_img = get_temp_images(temp_file) # 생성해준 이미지 파일에 이미지 저장
temp_img.seek(0) # 파일 형태기 때문에 첫 번째 요소 - 이미지 가져오기
self.article_data["image"] = temp_img # article_data 에 이미지 파일 추가
response = self.client.post(
path=reverse("article-view"),
data=encode_multipart(data=self.article_data, boundary=BOUNDARY),
content_type=MULTIPART_CONTENT,
HTTP_AUTHORIZATION=f"Bearer {self.access_token}", # header 에 로그인 인증 값 넣기
)
self.assertEqual(response.status_code, 201)