거북이반 - drf 게시글 테스트코드
오늘의 순서
- 회원정보 테스트코드
- article의 테스트코드
- setUpTestData
- 파이썬
- 클래스메소드
- 스태틱메소드
- article 테스트코드 2
🚩9강
- simple-jwt를 사용하여 로그인을 시도한 경우에는 토큰을 담아서 테스트를 진행해야 한다
- self.client 메서드로 테스트한 코드에서 나오는 값을 .data[response결과] 값으로 담아 변수로 초기화할 수 있음
# user.test
def test_get_user_data(self):
access_token = self.client.post(reverse('token_obtain_pair'),self.data).data['access']
response = self.client.get(
path=reverse('user_view'),
HTTP_AUTHORIZATION=f"Bearer {access_token}"
)
self.assertEqual(response.status_code, 200)
# self.assertEqual(response.data['username'], self.data['username'])
🚩10강
- 게시글 CRUD 테스트코드 작성준비
- setUp 메서드와 setUpTestData 메서드의 차이
- 셋업 메서드는 모든 메서드에 대해 실행될 때마다 한 번 실행되도록 되어 있다.
- 변경되지 않는 데이터에 대해서(같은 유저 아이디와 같은 예시)는 매번 한 번씩 실행될 필요는 없기에 setUpTestData 메서드에 적어준다!
- simple-jwt 토큰을 발행하고, 토큰을 넣은 요청과 함께 views.py에서 request.data로 로직을 구현하자
- 생각해야 할 것은 POSTMAN으로 어떻게 찍을 것인지 생각해야 한다
# articles.tests.py
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import User
# Create your tests here.
class ArticleCreateTest(APITestCase):
def setUp(self):
self.user_data = {'username': 'john', 'password':'johnpassword'}
self.article_data = {'title':'some title','content':'some content'}
self.user = User.objects.create_user('john','johnpassword')
self.access_token = self.client.post(reverse('token_obtain_pair'),self.user_data).data['access']
# articles.views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from articles.serializers import ArticleSerializer
from articles.models import Article as ArticleModel
# Create your views here.
class ArticleView(APIView):
def get(self, request):
articles = ArticleModel.objects.all()
serializer = ArticleSerializer(articles, many=True).data
return Response(serializer, status=status.HTTP_200_OK)
def post(self, request):
if not request.user.is_authenticated:
return Response({"message":"로그인 해주세요"}, 401)
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({"message": "글 작성 완료!!"})
else:
return Response({"message": f'${serializer.errors}'}, 400)
🚩11강
- 클래스메서드(class method)
- 예시) 사람 클래스와 메서드, 클래스메서드
- Person 클래스는 이름과 나이를 속성으로 받는
클래스 객체
다 - Person 클래스에는
display메서드
와fromBirthYear 클래스메서드
를 가지고 있다 class Person: def __init__(self, name, age): self.name = name self.age = age @classmethod def fromBirthYear(cls, name, birthyear): return cls(name, date.today().year - birthyear) def display(self): print(self.name + "'s age is" + str(self.age))
변수에 Person 클래스를 선언
하고 name과 age를 인자 값으로 넣어 사용할 수 있게 된 즉석 개체,인스턴스를 생성
했다.- 클래스 인스턴스가 된
변수 person은 클래스 내부의 함수, 메서드를 사용할 수 있게 되어
display() 의 형식으로 함수를 호출하여 이름과 나이가 어떻게 되는지 프린트 해 볼 수 있다. person = Person('Adam', 19) person.display()
- 변수 person1은
인스턴스를 생성하지 않은 상태
에서 바로 Person 클래스의클래스메서드인 fromBirthYear
를 name, birthyear 인자를 넣고바로 호출
했다. 클래스메서드
fromBirthYear는 입력한 인자와 함께 상위 클래스인 Person을cls 인자
로 받았다return cls
로 person1 변수로 초기화할 때 받았던 인자를 사용하여 클래스를 선언하는 형식에 맞게 값을 담아인스턴스를 생성
한다.- 클래스메서드 return cls로
Person 클래스 인스턴스가 선언되었기 때문에
,클래스 내부의 함수
인 display()를 변수 person1에서도사용할 수 있게 되었다!
person1 = Person.fromBirthYear('John', 1985) person1.display()
- Person 클래스는 이름과 나이를 속성으로 받는
🙄메서드가 있는데 왜 굳이 클래스메서드를 사용해야 하는가?
- 클래스메서드는 기존의 인스턴스를 선언하기 위한 인자 이외의 값을 받았을 때를 상정하여 작성할 수 있다고 생각한다!
- 위의 예시로는 사람의 나이와 이름을 받아야 하지만, 출생년도를 인자 값으로 받는 상황에서는 인스턴스를 선언할 수 없다!
- 따라서 클래스메서드를 통해서 다양한 케이스 처리를 해주는 것으로 생각하면 좋다!
🚩12강
- 스태틱 메서드(static method)
- 전역 클래스가 아닌 지역 클래스처럼 부모 클래스안에 스코프를 가둔다 (가독성 좋게하기 위해)
- 하나의 클래스 내부에서 사용될 수 있을 함수를 엮어서 볼 수 있도록 일반 메서드 또한 스태틱메서드로 사용할 수 있다
@staticmethod
def isAdult(age):
return age > 18
person1 = Person.fromBirthYear('황영상', 29) #클래스메서드의 활용
person1_is_adult = Person.isAdult(person1.age) #스태틱메서드의 활용
🚩13강
클래스메서드 setUpTestData와 메서드 setUp을 혼용해서 데이터 셋업하기
- setUpTestData에는 모든 테스트가 하나의 공통된 데이터를 인자로 받을 때 사용한다
- setUp 메서드는 client 메서드를 사용해서 테스트를 한 뒤 받아올 값과 같이 클래스 내부에서 사용하면 오류를 발생시키거나 한 번씩 각각 받아올 필요가 있을 때 사용한다
from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import User
# Create your tests here.
class ArticleCreateTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user_data = {'username': 'john', 'password':'johnpassword'}
cls.article_data = {'title':'some title','content':'some content'}
cls.user = User.objects.create_user('john','johnpassword')
def setUp(self):
self.access_token = self.client.post(reverse('token_obtain_pair'),self.user_data).data['access']
🚩14강
- 테스트코드 함수명은 test_ 로 시작하는것이 좋다
def test_fail_if_not_logged_in(self):
url =reverse("article_view")
response = self.client.post(url, self.article_data)
self.assertEqual(response.status_code, 401)
- 특정 앱만을 테스트 하고 싶을 때는 뒤에 앱 이름을 같이 적어 테스트를 실행한다
python manage.py test articles
🚩15강
- post 메서드 테스트
- 리스폰스에 주소, 아티클 데이터, 토큰을 담아서 테스트코드를 실행하기
def test_create_article(self):
response = self.client.post(
path = reverse("article_view"),
data = self.article_data,
HTTP_AUTHORIZATION = f"Bearer {self.access_token}"
)
self.assertEqual(response.data['message'], "글 작성 완료!!")
🚩16강
- 이미지를 포함한 게시글 작성 테스트
# 이미지 업로드
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from PIL import Image
import tempfile
- 임시 이미지파일 생성
- temporary file 만들기
- temp_file 이름 지정
- get_temporary_image 로 임의의 이미지를 가져오기(내장기능)
- 클래스 self 내부에 이미지 변수로 넣어두기
- 테스트코드에 멀티파트 데이터 선언
- 클라이언트 메서드로 실행할 내부 인자에 주소, 인코딩 데이터, 컨텐트 타입, 토큰을 넣어 테스트 실행
- assertEqual로 테스트 확인하기
def test_create_article_with_image(self):
temp_file = tempfile.NamedTemporaryFile()
temp_file.name = "image.png"
image_file = get_temporary_image(temp_file)
image_file.seek(0)
self.article_data["image"] = image_file
response = self.client.post(
path=reverse("article_view"),
data=encode_multipart(data=self.article_data),
content_type=MULTIPART_CONTENT,
HTTP_AUTORIZATION = f"Bearer {self.access_token}
)
self.assertEqual(response.data["message"], "글 작성 완료")
'개발_TIL' 카테고리의 다른 글
개발_TIL | 2022-07-19 (63) (0) | 2022.07.19 |
---|---|
개발_TIL | 2022-07-15 (62) (0) | 2022.07.15 |
개발_TIL | 2022-07-12 (59) (0) | 2022.07.12 |
개발_TIL | 2022-07-11 (58) (0) | 2022.07.11 |
개발_TIL | 2022-07-08 (57) (0) | 2022.07.08 |