์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- CI/CD
- ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ
- AQE
- k8s
- KDT_TIL
- Spark
- Salting
- Dag
- spark executor memory
- topic
- Spark Caching
- Kafka
- DataFrame Hint
- Speculative Execution
- redshift
- aws
- Spark Partitioning
- Kubernetes
- Airflow
- Spark ์ค์ต
- SQL
- Docker
- etl
- colab
- Spark SQL
- mysql
- disk spill
- ๋น ๋ฐ์ดํฐ
- backfill
- off heap memory
- Today
- Total
JUST DO IT!
[TIL]KDT_20230428 ๋ณธ๋ฌธ
๐ KDT WEEK 4 DAY 5 TIL
- RelatedField
- ํฌํ(Votes)๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
- Validation
- Testing
๐ฅ RelatedField
Serializer์์ ์ธ๋ํค๋ก ์ฐ๊ฒฐ๋ ๋ค๋ฅธ ํ๋๋ฅผ ๋ถ๋ฌ์ฌ ๋, ์ด๋ค ์ต์ ์ผ๋ก ๊ฐ์ ธ์ฌ์ง ์ด ๊ธฐ๋ฅ์ผ๋ก ์ ํ ์ ์๋ค.
1. PrimaryKeyRealatedField
PrimaryKey, ์ฆ id์ ๊ฐ์ ๋ณด์ฌ์ค๋ค.
2. StringRelatedField
ํด๋น ๋ชจ๋ธ(questions)์ ์ ์๋ __str__์ ๋ฐ๋ผ ์ด๋ฆ์ผ๋ก ๋ณด์ฌ์ค๋ค.
3. SlugRelatedField
ํด๋น ์ค๋ธ์ ํธ(question)์ ํน์ ํ๋ ๊ฐ(pub_date)๋ฅผ ๋ณด์ฌ์ค๋ค.
4. HyperlinkedRelatedField
ulrs.py์ name๊ณผ ์ผ์นํ๋ view_name์ ์์ฑํ๋ฉด, ํด๋น ์ค๋ธ์ ํธ(question)๊ณผ ์ฐ๊ฒฐ๋๋ url์ ๋ณด์ฌ์ค๋ค.
๊ฒฐ๊ณผ
์ด๋ฒ์ Serializer๋ฅผ ์ ์ํ์ฌ ๊ด๋ จ๋ชจ๋ธ ํ๊ธฐํด๋ณด๊ธฐ
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ['choice_text', 'votes']
class QuestionSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
choices = ChoiceSerializer(many=True, read_only = True) # Question์์ choice๋ฅผ ํ์ํ๊ธฐ ์ํด์
class Meta:
model = Question
fields = ['id', 'question_text', 'pub_date','owner', 'choices'] # ModelSerializer๋ฅผ ํตํด ์๋์ผ๋ก ์์ฑ
Question์ ์ฐ๊ฒฐ๋ choice๋ค์ ๋ํ๋ด๊ธฐ ์ํด์ ChoiceSerializer๋ฅผ ๋ง๋ค๊ณ , ์์ฒ๋ผ ์์ฑํ๋ค.
choices = ChoiceSerializer๊ณผ fields์ 'choices'๋ฅผ ์ถ๊ฐํด์ฃผ์๋ค.
+
์ฌ์ค choices๋ก ์ด๋ฆ์ ์ ํ ๊ฒ์, Choice ๋ชจ๋ธ์์ ์ ์ํ ๋ถ๋ถ๊ณผ ๊ด๋ จ์ด ์๋ค.
Chocie ๋ชจ๋ธ์์์ question์ related_name์ 'choices'๋ก ์ ์ํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ์ผ์ด๋ค.
์์ฒ๋ผ related_name์ ์ ์๊ฐ ์๋ค๋ฉด, shell์์ ๋์ํ๋ฏ choice_set์ผ๋ก ๋ถ๋ฌ์์ผํ๋ค.
๐ฆ ํฌํ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
๊ธฐ๋ฅ ๊ตฌํ์ ์ํด ๋๊ฐ ์ด๋ค ์ง๋ฌธ์ ์ด๋ค ๊ฒ์ ํฌํํ๋์ง๋ฅผ ๋ด๊ณ ์๋ ๊ฐ์ฒด, Vote ๋ชจ๋ธ์ ๋ง๋ค์ด๋ณด์.
class Vote(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice = models.ForeignKey(Choice, on_delete=models.CASCADE)
voter = models.ForeignKey(User, on_delete=models.CASCADE)
# question๊ณผ voter์ ๋ํด ํ๋์ ๋ ์ฝ๋๋ฅผ ์์ฑ
# voter๊ฐ ํ๋์ฉ๋ง ๋ง๋ค ์ ์๊ฒ ์ ์ฝ์กฐ๊ฑด์ ๋ง๋ค์ด์ฃผ๋ ๊ฒ์.
class Meta:
constraints = [
models.UniqueConstraint(fields=['question', 'voter'], name='unique_voter_for_questions')
]
ํ๋์ User๊ฐ ๊ฐ์ Question์ ์ฌ๋ฌ๋ฒ ํฌํํ๋ ๊ฒ์ ๋ง๊ธฐ ์ํด, ์ ์ฝ์กฐ๊ฑด(Constratins)๋ฅผ ์์ฑํด์ฃผ์๋ค.
์ ์ฝ์กฐ๊ฑด์ ์์ฒ๋ผ, Meta ํด๋์ค์์ ๋ฆฌ์คํธํํ๋ก ๊ตฌํํ๋ค.
์ด๋ ๊ฒ question๊ณผ voter๋ฅผ ๋ฌถ์ด๋์ผ๋ฉด, ํ๋์ User๊ฐ Choice๋ง ๋ฐ๊ฟ์ ๊ฐ์ Question์ ํฌํํ ์ ์๊ฒ๋ ๊ฒ์ด๋ค!
์ด์ Choice์์๋ ์์ ์ voteํ๋๊ฐ ์๋ Vote ๋ชจ๋ธ์ ํตํด ํฌํ์๋ฅผ ๋ณด์ฌ์ค์ผํ ๊ฒ์ด๋ค.
class ChoiceSerializer(serializers.ModelSerializer):
votes_count = serializers.SerializerMethodField() # ๊ฐ์ด ๋ฉ์๋์ ์ํด์ ๊ฒฐ์ ๋จ
class Meta:
model = Choice
fields = ['choice_text', 'votes_count']
def get_votes_count(self, obj): # obj = choice
return obj.vote_set.count() # choice๊ฐ vote์ ์ธ๋ํค๋ก ์ฐ๊ฒฐ๋์ด์๊ธฐ ๋๋ฌธ์ _set ์ฌ์ฉ
serializers.SerializerMethodField()๋ ์ด ๋ณ์๊ฐ ํจ์์ ๊ฐ์ ์ํด ๊ฒฐ์ ๋๋ค๊ณ ๋งํด์ฃผ๋ ๊ฒ์ด๋ค.
์๋์ get_๋ณ์์ด๋ฆ()์ ๋ฉ์๋์์ return ๊ฐ์ ํตํด votes_count์ ์ ์ฅ๋ ๊ฒ์ด๋ค!
ํ์คํธ๋ฅผ ์ํด Shell์์ user,question,choice๋ฅผ ์์๋ก ํ๋ ์ ์ฅํด๋๊ณ ์๋์ ๊ฐ์ด ์ ๋ ฅํ๋ค.
>>> Vote.objects.create(voter=user,question=question,choice=choice)
<Vote: Vote object (1)>
๊ฒฐ๊ณผ
Vote ์์ฑ ๋ฐ ์์ API ๋ง๋ค๊ธฐ
API ์์ฑ์ ์ํด ๋จผ์ Serializer๋ฅผ ์์ฑํด์ผํ๋ค.
โถ polls_api/serializers.py
from polls.models import Question,Choice, Vote
class VoteSerializer(serializers.ModelSerializer):
voter = serializers.ReadOnlyField(source='voter.username')
class Meta:
model = Vote
fields = ['id', 'question', 'choice', 'voter']
voter๋ ๋ก๊ทธ์ธ ์ฌ์ฉ์๋ฅผ ํ ๋๋ก ์ ์๋๊ฑฐ๋ ์์ ๋๋ฏ๋ก ReadonlyField๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
๋ค์์ผ๋ก ํ๋ฉด ๊ตฌํ์ ์ํด views.py์ Question์ฒ๋ผ VoteList์ VoteDetail์ ๋ง๋ค์๋ค.
โถ polls_api/views.py
#๋ด๊ฐ ์์ฑํ Vote๋ค๋ง ๋ณด์ฌ์ฃผ๋ ๊ธฐ๋ฅ
class VoteList(generics.ListCreateAPIView):
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated] # ๋ก๊ทธ์ธํ ์ ์ ๋ง ๋ณผ ์ ์๋๋ก ์ ํ
def get_queryset(self, *args, **kwargs): #๋ฆฌ์คํธ๋ฅผ ํํํ ๋ ์ฌ์ฉํ ์ฟผ๋ฆฌ์
์ ์
return Vote.objects.filter(voter=self.request.user)
def perform_create(self, serializer):
serializer.save(voter=self.request.user)
class VoteDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Vote.objects.all()
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated, IsVoter] #ํฌํํ ์ฌ๋๋ง CRUD ๊ฐ๋ฅํด์ผํจ
VoteList๋ vote๋ค์ ๋ชฉ๋ก์ ๋ณด์ฌ์ค ๊ฒ์ด๋ค.
vote๊ฐ ์์ฑ๋ ๋๋ ํ์ฌ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ผ ํ๋ฏ๋ก perform_create๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํด์ผํ๋ค.
VoteDetail๋ vote id๋ฅผ ํตํด ๋ง๋ค์ด์ง ์์ธํ์ด์ง์ด๋ค.
์ฌ๊ธฐ์๋ permission์ IsVoter๋ผ๋ ํน๋ณํ ํจ์๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
โถ polls_api/permissions.py
class IsVoter(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.voter == request.user # ์ค๋ธ์ ํธ์ ์์ ์๊ฐ ์์ฒญํ ์ฌ์ฉ์ ์ธ๊ฐ? ๋ง์ผ๋ฉด True
permissions์์ ๋ฏธ๋ฆฌ ์ ์ํด๋ ํจ์๋ฅผ ๊ฐ์ ธ๋ค ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
views.py๋ฅผ ์ ์ํ์ผ๋, urls.py์ path๋ฅผ ์ง์ ํ๋ ๊ฒ๋ ์์ง ๋ง์์ผ ํ๋ค.
urlpatterns = [
...
path('vote/', VoteList.as_view()),
path('vote/<int:pk>/', VoteDetail.as_view()),
]
๊ฒฐ๊ณผ
๐จ Validation
๋ช ๊ฐ์ง ์ค๋ฅ๋ฅผ ์์ ํด๋ณด๊ฒ ๋ค.
1. question๊ณผ user๊ฐ ๊ฐ์ ๊ฐ์ด ๋ค์ด์์ ๋ 400 ์๋ฌ๊ฐ ์๋ 500 ์๋ฌ๊ฐ ๋ํ๋๋ ํ์ ๋ฐฉ์ง
โถ polls_api/serializers.py
from rest_framework.validators import UniqueTogetherValidator
class VoteSerializer(serializers.ModelSerializer):
class Meta:
model = Vote
fields = ['id', 'question', 'choice', 'voter']
validators = [
UniqueTogetherValidator(
queryset = Vote.objects.all(),
fields=['question', 'voter']
)
]
Serializer์ validators๋ฅผ ์ถ๊ฐํด์ฃผ๋ฉด 400 Bad request ์๋ฌ๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๋ํ๋๋ค.
ํ์ง๋ง ์ด๋ฒ์๋ ์๋ฌ๋ฉ์์ง๊ฐ ์ด์ํ๋ค.
"voter" : "This field is required."
๋ผ๊ณ ๋์ค์ง๋ง, voter๋ ์๊ด์ด ์๊ณ question๊ณผ voter์ UniqueVailidation์ ๋ํ ์ค๋ฅ๋ก ๋ฐ๊ฟ์ค์ผํ๋ค.
โถ polls_api/views.py
from rest_framework import status
from rest_framework.response import Response
class VoteList(generics.ListCreateAPIView):
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated]
def get_queryset(self, *args, **kwargs):
return Vote.objects.filter(voter=self.request.user)
def create(self, request, *args, **kwargs):
new_data = request.data.copy()
new_data['voter'] = request.user.id
serializer = self.get_serializer(data=new_data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
views.py์์ VoteList ํด๋์ค์ create ํจ์๋ฅผ ์ค๋ฐ๋ผ์ด๋ฉํด์ฃผ์ด์ผํ๋ค.
์๋ฌ์ ์ด์ ๊ฐ ๋ถ๋ชจ ํด๋์ค์์ ์ ์๋ create ๋ฉ์๋์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ฐ๋ฆฌ๊ฐ ์ค๋ฒ๋ผ์ด๋ฉ perform_create ๋ฉ์๋์ user ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ฃผ์๋ฐ,
create ๋ฉ์๋์์๋ .is_valid๊ฐ .perform_create ๋ฉ์๋๋ณด๋ค ๋จผ์ ์คํ๋๊ธฐ ๋๋ฌธ์ user ๊ฐ์ด ์๋ค๊ณ ์๋ฌ๊ฐ ๋จ๋ ๊ฒ์ด๋ค.
๋ฐ๋ผ์ ์์ฒ๋ผ createํจ์์์ perfrom_create ๋ฉ์๋์์ user ๊ฐ์ ๋ฃ์ง์๊ณ ,
์ ์ด์ new_data ๋ณ์๋ฅผ ๋ง๋ค์ด ์์ฒญ๋ฐ์ user ๊ฐ์ ๊ทธ๋๋ก ๋ฃ์ด์ค๋ค.
+ ๊ทธ๋ฆฌ๊ณ , serializer์๊ฒ voter๊ฐ์ด ์ ์ ๋ฌ๋๋๋ก VoteSerializer์ vote์ Readonly ์ ํ๋ ์์ ์ค์ผํ๋ค.
2. ๋ก๊ทธ์ธ๋ user๊ฐ ์์ ์ vote ๊ฐ์ฒด๋ฅผ ๋ค๋ฅธ user์ ์ด๋ฆ์ผ๋ก ๋ฐ๊ฟ ์ ์๋ ๋ฌธ์
โถ polls_api/views.py
class VoteDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Vote.objects.all()
serializer_class = VoteSerializer
permission_classes = [permissions.IsAuthenticated, IsVoter] #ํฌํํ ์ฌ๋๋ง CRUD ๊ฐ๋ฅํด์ผํจ
def perform_update(self, serializer):
serializer.save(voter=self.request.user)
perform_update ๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉํ๋ค.
์ด๋ ๊ฒํ๋ฉด, ์ ์ ๊ฐ ๋ค๋ฅธ ์ ์ ์ ์ด๋ฆ์ ๋ฃ์ ์ ์์ด๋ ๋ก๊ทธ์ธ๋ ์ ์ ์ ์ด๋ฆ์ผ๋ก ๊ณ ์ ๋์ด ๋ค์ด๊ฐ๊ธด ํ๋ค..
3. vote๋ฅผ ์์ ํ ๋ question๊ณผ choice๊ฐ ์๋ก ๋ง์ง ์๋๋ฐ ์์ ๋๋ ๋ฌธ์
โถ polls_api/serializers.py
class VoteSerializer(serializers.ModelSerializer):
def validate(self, attrs): # validation ์ํ, attrs์ ๋ฐ์ดํฐ๋ฅผ ๋ด์์จ๋ค.
if attrs['choice'].question.id != attrs['question'].id:
raise serializers.ValidationError("Qeustion๊ณผ Choice๊ฐ ์กฐํฉ์ด ๋ง์ง ์์ต๋๋ค.")
return attrs
class Meta:
model = Vote
fields = ['id', 'question', 'choice', 'voter']
validators = [
UniqueTogetherValidator(
queryset = Vote.objects.all(),
fields=['question', 'voter']
)
]
VoteSerializer์ validate ํจ์๋ฅผ ์ถ๊ฐํด์ฃผ์ด์ผํ๋ค. ์ด๋ validation์ ์ํํ๋ ํจ์์ด๋ค.
Serializer์์ validation์ ์ํํจ์ผ๋ก์จ ์ค๋ฅ๊ฐ๋๋ฉด ํด๋น ์ค๋ฅ ํ ์คํธ๋ฅผ ๋์ธ ์๊ฐ ์๋ค.
๐ง Testing
์ปดํจํฐ๊ฐ ์ค์ค๋ก ํ ์คํธ๋ฅผ ๋๋ ค์ฃผ๋ ์๋ํ ๊ธฐ๋ฅ
django์์ ์ง์ํ๋ TestCase์ rest_framework์ APITestCase๋ฅผ ์ด์ฉํด์ ์๋ํ ํ ์คํธ ํ์ผ์ ๋ง๋ค์ด๋ณธ๋ค!
Test ์ฝ๋๋ฅผ ์์ฑํ ๋๋ ๋ค์์ ์ฃผ์ํ๋ฉด์ ์์ฑํ๋ค.
- ์ ์๋ ํ ์คํธ ํจ์์ ์ด๋ฆ์ "test_"๋ก ์์ํด์ผํ๋ฉฐ, ๊ทธ ์ด๋ฆ์ ์ ๋ช ์ํด์ผ ํ๋ค.
- TestCase๋ Test๋ฅผ ์ํ ๋ณ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ด์ฉํ๋ค.
- ๊ฐ ํ ์คํธ๋ ๋ชจ๋ ๋ณ๊ฐ๋ก ๋์ํ๋ค.
ํ ์คํธ๋ฅผ ์ํ assert ๋ฉ์๋
- .assertEqual() : ๋ ์ธ์๊ฐ ์๋ก ๊ฐ์์ง ํ์ธํ๋ค. == ์ ๊ฐ์ด ๊ฒ์ฌํ๋ค.
- .assertIsNotNone() : ์ธ์๊ฐ None์ด ์๋๋ฉด True๋ฅผ ๋ฆฌํดํ๋ค.
- .assertTrue() : ์ธ์๊ฐ์ด True์ธ์ง ํ์ธํ๋ค.
- .assertLess(): ๋ ๊ฐ์ ์ธ์๋ฅผ ๋ฐ๋๋ค. ์ค๋ฅธ์ชฝ์ ์ธ์๊ฐ ์ผ์ชฝ์ ์ธ์๋ณด๋ค ์์์ง ํ์ธํ๋ค.
ํ ์คํธ์ ๋์ ํ์ธ์ shell์์
>>> python manage.py test
๋ก ํ์ธํ ์ ์๋ค.
โถ polls_api/tests.py
from django.test import TestCase
from polls_api.serializers import QuestionSerializer
class QuestionSerializerTestCase(TestCase):
# def test_a(self): # test_ ๋ก ์์ํ๋ ํจ์๋ง ํ
์คํธ๋ผ๊ณ ์ธ์ํจ # ์ฑ๊ณตํ๋ฉด . ์คํจํ๋ฉด F
def test_with_valid_data(self):
serializer = QuestionSerializer(data={'question_text' : 'abc'})
self.assertEqual(serializer.is_valid(), True) # question_text๋ฅผ ์
๋ ฅํ๊ณ createํ ๋, is_validํ ์ํฉ์ธ๊ฐ?
new_question = serializer.save() # id๊ฐ ์๋์ ์ฅ๋ ๊ฒ์
self.assertIsNotNone(new_question.id) # id๊ฐ ๋น์ด์๋๊ฐ?
# question_text๊ฐ ๋น์ด์๋๋ก ์์ฑํ๋ฉด is_valid()๊ฐ False์ธ๊ฐ?
def test_with_invalid_data(self):
serializer = QuestionSerializer(data={'question_text' : ''})
self.assertEqual(serializer.is_valid(), False)
QuestionSerializer๋ฅผ ํ ์คํธํ๊ธฐ ์ํ ์ฝ๋์ด๋ค.
Test๋ฅผ ํด๋ณด๋, ๋ชจ๋ ํจ์คํ๋ค.
class VoteSerializerTest(TestCase):
def setUp(self): # ํ
์คํธ๊ฐ ์คํ๋ ๋๋ง๋ค ํ๋ฒ์ฉ ๋ฐ๋ณต๋์ด ์คํํจ, *self๋ฅผ ์ฌ์ฉํจ์ ์ฃผ์* ํ
์คํธ๋ง๋ค ๋
๋ฆฝ์ ์ํ
self.user = User.objects.create(username='testuser')
self.question = Question.objects.create(
question_text ='abc',
owner = self.user
)
self.choice1 = Choice.objects.create(
question=self.question,
choice_text = '1'
)
# create vote Test
def test_vote_serializer(self):
data ={
'question' : self.question.id,
'choice' : self.choice1.id,
'voter' : self.user.id
}
serializer = VoteSerializer(data= data)
self.assertTrue(serializer.is_valid())
vote = serializer.save()
self.assertEqual(vote.question, self.question)
self.assertEqual(vote.choice, self.choice1)
self.assertEqual(vote.voter, self.user)
# question, user์ UniqueValidation Test
def test_vote_serializer_with_duplicate_vote(self): # ๋ฉ์๋๋ฅผ ์ ์ ์ด์ค์ผ ์๋ฌ๋ฐ์ํ์ ๋ ์๊ธฐ ์ฌ์
choice2 = Choice.objects.create( # ์๋กญ๊ฒ ๋ค์ด๊ฐ Vote์ฉ
question=self.question,
choice_text = '2'
)
Vote.objects.create(question=self.question, choice=self.choice1, voter=self.user) # ๋ฏธ๋ฆฌ ํ๋ ๋ง๋ค์ด๋
data ={
'question' : self.question.id,
'choice' : choice2.id,
'voter' : self.user.id
}
serializer = VoteSerializer(data= data)
self.assertFalse(serializer.is_valid()) # question๊ณผ user๊ฐ ๋์ผํ vote๋ฅผ ๋ ์์ฑํ ์ ์์๊น?
# question๊ณผ choice์ unmatch Test
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 = '1'
)
data ={
'question' : self.question.id,
'choice' : choice2.id,
'voter' : self.user.id
}
serializer = VoteSerializer(data= data)
self.assertFalse(serializer.is_valid())
VoteSerializer๋ฅผ ํ ์คํธํ๋ ์ฝ๋์ด๋ค.
์์ฒญ ๊ธธ์ง๋ง ๋๋ถ๋ถ ๋ณ์๋ค์ ์ด๊ธฐํํ๋ ๋ด์ฉ์ด๊ณ , ์ง๊ด์ ์ด๋ค.
์ค์ํ๊ฑด, setUp() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ค.
- setUp() ๋ฉ์๋๋ ๊ฐ ํ ์คํธ๊ฐ ์์๋๊ธฐ ์ ์ ํ๋ฒ์ฉ ์คํ๋๋ ๋ฉ์๋์ด๋ค.
- ๋ฐ๋ณต๋๋ ์ฝ๋๋ ์์ฃผ ์ด๊ธฐํ๋๋ ๋ณ์๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ์ข๋ค.
- ์ฌ์ฉ๋ ๋ณ์๋ ๊ทธ ํด๋์ค์์์ self.๋ณ์๋ช ์ ํตํด ๋ถ๋ฌ์์ผํ๋ค.
์ด๋ฒ์ APITestCase๋ฅผ ์ด์ฉํ์ฌ View๋ฅผ ํ ์คํธํ ์ฝ๋์ด๋ค.
# View์ ๊ฒฝ์ฐ APITestCase๊ฐ ํ์
class QuestionListTest(APITestCase):
def setUp(self):
self.question_data = {'question_text' : 'some question'}
self.url = reverse('question-list') # ๋ฉ์๋์์์๋ reverse.lazy๊ฐ ์๋ reverse ์ฌ์ฉํ๊ธฐ.
def test_create_question(self):
user = User.objects.create(username = 'testuser', password ="testpass")
self.client.force_authenticate(user=user) # ์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์ธ ์ํค๋ ๊ธฐ๋ฅ (APITestCase ๊ธฐ๋ฅ)
response = self.client.post(self.url, self.question_data) # ํด๋น ๋ฐ์ดํฐ๋ฅผ url๋ก post ์์ฒญ
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Question.objects.count(), 1)
question = Question.objects.first()
self.assertLess((timezone.now() - question.pub_date).total_seconds(), 1) # assertLess๋ ๋ค์ ์ธ์๋ณด๋ค ์์๊ฐ? ํ์ธํจ
# ์ฌ์ฉ์ ๋ก๊ทธ์ธ์์ด question์ ๋ง๋ค์์ ๋
def test_create_question_without_authentication(self):
response = self.client.post(self.url, self.question_data)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_list_questions(self):
question = Question.objects.create(question_text='Question1')
Choice.objects.create(question=question, choice_text='choice1')
Question.objects.create(question_text='Question2')
response = self.client.get(self.url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data),2)
์ฌ์ฉ์๋ฅผ ๋ก๊ทธ์ธ ์ํ๋ก ๋๋ ํจ์๋ฅผ ์ฌ์ฉํ๊ธฐ์ํด APITestCase์ ์์์ด ํ์ํ๋ค.
+ ํ์ด์ฌ์์ ์์ฑํ ํ ์คํธ ์ฝ๋์ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ธก์ ํ ์ ์๋ ๋๊ตฌ๊ฐ ์๋ค.
>>> pip install coverage
>>> coverage run manage.py test
>>> coverage report
๋ ๋ฒ์งธ ๋ช ๋ น์ด๋ก test๋ฅผ ์คํํ๊ณ , ์ธ ๋ฒ์งธ ๋ช ๋ น์ด๋ก test์ ๊ฒฐ๊ณผ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ํ์ธํ ์ ์๋ค.
๊ฒฐ๊ณผ
๐ค ๊ณต๋ถํ๋ฉด์ ์ด๋ ค์ ๋ ๋ด์ฉ
์ค๋์ ์์ฑํ ์ฝ๋๋ฅผ ๋ณด์ํ๊ฑฐ๋ ํ ์คํธํด๋ณผ ์ ์์๋ค.
์ด๋ป๊ฒ๋ณด๋ฉด ๊ฐ์ฅ ๊ท์ฐฎ์ง๋ง ์ค์ํ ์์ ์ด๋ผ๊ณ ์๊ฐํ๋ค.
๋ฐฑํ๋ก ์์ฑ๋ ์ฝ๋๋ ์๋ ๋ฒ์ด๋๊น.. ๐
'TIL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[TIL]KDT_20230502 (0) | 2023.05.02 |
---|---|
[TIL]KDT_20230501 (0) | 2023.05.01 |
[TIL]KDT_20230427 (0) | 2023.04.27 |
[TIL]KDT_20230426 (0) | 2023.04.26 |
[TIL]KDT_20230425 (0) | 2023.04.25 |