학습주제
투표와 테스팅
Testing Serializers
학습내용
이번엔 VoteSerializer에 대해 테스트를 구현하면서 테스트의 기능에 대해 좀 더 자세히 알아본다.
VoteSerializer에는 validation이 두가지가 구현되어 있다.
UniqueTogetherValidator라고 한 사람이 하나의 question에 대해 vote를 하나만 생성할 수 있도록 하게 하는 validation.
validate 메소드를 오버라이드해서 choice.question.id와 question.id가 맞지 않는 경우
이 두가지를 중점으로 테스트 해본다.
test.py로 넘어와 필요한 시리얼라이저를 임포트한다.
from polls_api.serializers import QuestionSerializer, VoteSerializer
from polls.models import Question, Choice, Vote
class VoteSerilizer(TestCase):
생성
class VoteSerializer(TestCase):
def test_vote_serializer(self):
user = User.objects.create(username='testuser')
question = Question.objects.create(
question_text='abc',
owner=user,
)
choice = Choice.objects.create(
question=question,
choice_text='1',
)
data = {
'question': question.id,
'choice': choice.id,
'voter': user.id,
}
serializer = VoteSerializer(data=data)
self.assertTrue(serializer.is_valid())
vote = serializer.save()
self.assertEqual(vote.question, question)
self.assertEqual(vote.choice, choice)
self.assertEqual(vote.voter, user)
assertTrue
는 EqualTrue와 같은 의미로 동작함.
F가 아닌 E. 에러가 발생했다.
class VoteSerializer(TestCase):
뒤에 Test를 붙이지 않았다. 자동완성을 쓰다보면 저러헥 한두개씩 빼먹는다.
VoteSerializer가 데이터로 각 모델의 id만 받는 이유는 Vote모델 생성시, 각 필드를 외래키 참조로 만들었기 때문. 따라서 해당하는 필드의 id만 넘겨줘도 VoteSerializer는 그 필드를 찾아서 생성함.
지금까지는 정상적인 경우였다.
이미 만들었던 투표에 대해 같은 사용자가 다시 투표할 때, UniqueTogetherValidator
를
메소드 이름 정의를 명확하게 해주면 실패했을 때 어디에서 실패했는지 바로 알 수 있다.
choice를 2개 생성한다. 그리고 이미 vote가 만들어진 상황이어야 한다.
Vote.objects.create(question=question, choice=choice, voter=user)
임의의 Vote를 1개 생성한다.
시리얼라이저에 또다른 choice인 choice1을 주고 똑같은 유저가 똑같은 question에 대해 같은 시도를 해본다.
self.assertFalse(serializer.is_valid())
아까 True와 달리, 이미 투표를 한 상황에서 거기에 또다른 옵션으로 또 투표를 하려고 하는 시리얼라이저를 만들고 is_valid 호출
` self.assertFalse(serializer.is_valid())`
is_valid()가 False가 나왔다는 소리.
왜 valid 하지 않냐면 UniqueTogetherValidator가 동작했기 때문
만일 Vote.objects.create(question=question, choice=choice, voter=user)
지우면
이 시나리오에서는 우리가 투표를 만들고 그다음 시리얼라이저를 통해 시리얼라이즈를 했더니 is_valid()가 False가 나옴.
미리 만들었던 부분을 지워버리면,
실패라고 뜬다.
is_valid가 True가 떠버림.
이걸 매번 브라우저로 하기엔 귀찮은 작업임.
Django의 TestCase 클래스는 테스트를 위한 임시 데이터베이스를 생성하며, 이 데이터베이스는 실제 데이터베이스와는 분리되어 있습니다. Vote.objects.create가 호출될 때 데이터베이스에 저장되는 것은 아니며, 이 메소드가 반환하는 Vote 인스턴스는 메모리에서만 존재합니다.
Serializer 객체 또한 단순히 파이썬 객체를 직렬화하고 역직렬화하는 기능을 수행하며, 데이터베이스와는 직접적인 관계가 없습니다. 따라서 Serializer 객체의 동작도 테스트용 메모리 상에서 이루어지며, 실제 데이터베이스와는 분리됩니다.
맞아요. 시리얼라이저의 save() 메소드가 호출될 때, 인스턴스가 생성되고 데이터베이스에 저장됩니다. create()나 update() 메소드를 사용할 때도 마찬가지입니다. 이전에 말씀드린 것처럼, 시리얼라이저는 오로지 데이터의 직렬화와 역직렬화를 수행하기 위한 도구일 뿐, 실제 데이터베이스 작업은 이를 호출한 뷰 등의 다른 부분에서 이루어집니다.
미리 user, question, choice만들고 투표를 한상황에서 한번 더 투표하는 상황을 구현하였다.
두 메소드를 보면 반복되는 코드가 있다. 반복되는 코드를 재사용하기 위해 setUp
메소드를 제공하고 있다. 각 테스트 케이스가 실행될 때마다 한번 반복해서 실행하게 된다.
이렇게 문장이 두번 출력되는 것을 확인할 수 있다.
대신 setUp에 넣으려면 self.을 앞에 붙여서 객체를 사용할 수있다.
Creating test database for alias 'default'..
Destroying test database for alias 'default'..
테스트를 위한 별도의 데이터베이스를 만듦
이 테스트를 수행할 때 setUp에 의해서 데이터를 만들었다고 해서 그내용이 다음 테스트를 할 때도 남아 있는 것이 아님. 각 테스트 메소트에서 setup이 각기 한번씩 총 2번 실행됨.
실제로도 setUp이 매 메소드마다 실행되는지 확인해본다.
self.assertEqual(User.objects.all().count(), 1)
현재 데이터베이스에 지난 메소드 실행 후 유저가 생성되었는지 확인. 만일 setup이 초기화되지 않고 남아있다면 두 테스트 메소드 중 1개는 유저가 2개임.
문제없이 잘 실행된다. 유저는 1명. 즉 각 테스트 앞에서 한번 수행, 그 결과는 다음 테스트 수행 전에 초기화.
마지막으로 validate 조건 중 choice.question.id, question.id가 맞지 않을 때 is_valid()가 False로 나오는 지 확인.
setUp에 만들어진게 있기 때문에, question, choice를 1개씩 더 생성한다.
def test_vote_serializer_with_unmatched_question_and_choice(self):
question2 = Question.objects.create(
question_text='abc',
owner=self.user
)
choice2 = Choice.objects.create(
question=question2,
choice_text='4'
)
data = {
'question': self.question.id,
'choice': choice2.id,
'voter': self.user.id,
}
serializer = VoteSerializer(data=data)
self.assertFalse(serializer.is_valid())
data = {
'question': self.question.id,
'choice': choice2.id,
'voter': self.user.id,
}
보면 question은 setUp에서 생성. choice는 question2.id를 갖는다.
이때는 self.assertFalse(serializer.is_valid())
가 False가 나와야한다. is_valid()를 통과할 것으로 예상되기 때문.
에러가 발생했다.
setUP은 매 메소드마다 초기화되서 실행됨.
test를 위한 DB가 존재. 기존 DB와 연결 X
assertTrue, assertFalse
다음은 View에 대한 테스트를 알아본다.