2022. 11. 17. 08:40ㆍ스파르타코딩클럽[AI트랙 3기]/장고
1.drf에서 test코드 작성하기
-작업진행 방식 : 구현 > 웹브라우저로 확인 > 개선점 찾기
-문제점 : 시간낭비, 복잡도증가, 허점
-테스트 코드
파이선 유니테스트 모듈
2.프로젝트 설정과 첫 테스트코드
-프로젝트 코드
1)가상환경설정, 실행
2)패키지 설치 requirements.txt
3)python manage.py test
4)앱들어가서 test.py 확인하기
*test.py
class TestView(TestCase):
def test_two_is_three(self):
self.assertEqual(2,3)
>>>python manage.py test > failed 뜸
def test_two_is_two(self):
self.assertEqual(2,2)
3.장고에서 쓸 수 있는 테스트툴들
drf에서 테스팅하기 drf testing 구글링
장고 drf에서 사용하는 툴 > unitest 또는 pytest (설치 필요)
4.회원가입 테스트
1)user url 만지기
*users > urls.py
path(‘’,views.UserView.as_view(), name=“user_view”),
*test.py
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
class UserRegisterationAPIViewTestCase(APITestCase):
def test_registration(self):
url = reverse(“user_view“)
user data = {
“username”:“testuser”
“fullname”:“테스터”
“email”:“test@testuser.com”
“password”:“password”
}
response = self.client.post(rul, user_data)
self.assertEqual(response.status_code, 200)
>python manage.py test 하면 결과 나옴. 무슨에러인지 확인하고 싶으면 self 윗줄에 print(response.data)
5.로그인테스트
class는 그대로 가져오고
def test_login(self):
url = reverse(“token_obtain_pair“)
user data = {
“username”:“testuser”
“fullname”:“테스터”
“email”:“test@testuser.com”
“password”:“password”
}
response = self.client.post(rul, user_data)
self.assertEqual(response.status_code, 200)
401 에러 나옴. 레즈스트레이션에서 정상적으로 등록되었음에도 불구하고 왜 없을까?
6.setup 메소드
테스트에서는 메소드 하나를 실행할때마다 디비를 임시로만들어서 확인하고 없애버림. 그래서 디비에 안들어온다고생각하면 됨(모든 테스트는 독립적). 따라서 test_login에서는 데이터가 없는 상태라 위와같이 오류가 나옴.
def setup메소드는 모든 테스트실행 전에 실행됨.
+)def teatdDown() : 마지막으로 실행하는 것.
7setup을 이용한 로그인테스트
위에 로그인 테스트 지우고 새로 클래스 생성
class LoginUserTest(APITestCase):
def setUp(self):
self.data = {‘username’:‘john’,‘password’:‘johnpassword’}
self.user = User.objects.create_user(‘john’,‘johnpassword’) #model의 def create_user를 씀. username과 password 받아줌.
def test_login(self):
response = self.client.post(reverse(‘token_obtain_pair’), self.data)
print(response.data[“access”])
self.assertEqual(response.status_code, 200)
#모델에 print 가입이 있어서 가입도 나오는데 이부분도 지워줘야함.
8.drf 테스트코드 작성하기 ot
9.사용자 정보 가져오기 테스트
class LoginUserTest에서 이미 setup을 해뒀기 때문에 아래에 바로 생성하면 됨.
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”), #accesstoken을 해더에 싣어서 get요청을 ser_view url에
HTTP_AUTHORIZATION=f“Bearer {acess_token}”
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data[‘username’], self.data[‘username’])
>python manage.py test users #users에있는 test만 진행
10. setup test data
*article > test.py
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from user.models import User
class ArticleCreateTest(APITestCase):
def setUp(self):
self.user_data = {‘username’:‘john’,‘password’:‘johnpassword’}
self.article_data = {‘title’:‘some title’,‘content’:‘somecontent’}
*articles>views.py
def post
if not request.user.is_authenticated:
return Response{“message”:“로그인해주세요”}, 401)
seliaizer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({“message”:“글작성완료”})
else:
return Response({“message”:f’${serializer.errors}’}),400)
*test.py
def setUp(self):
self.user_data = {‘username’:‘john’,‘password’:‘johnpassword’}
self.article_data = {‘title’:‘some title’,‘content’:‘somecontent’}
self.user = User.objects.create_user(‘john’,‘johnpassword’)
self.access_token=self.client.post(reverse(‘token_obtain_pair’),self.data).data[‘access’]
>셋업하고 한번만쓰는 것이 아니라 계속 쓰게 하기 def setUpTestData
11.class method
12.static method
@staticmethod
def isAdult(age):
return age > 18
self와 class가 안들어감. 굳이 안에 쓰는 것은 그냥 class 안에서 정의해주고 사용하게끔하는 것(편의를 위해 넣어둔 것). 반면 classmethod는 반드시 거기에 써줘야함.
13.다시 setuptestdata
setupdata를 class안에 넣어줌.
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): #client는 classmethod아니기 때문에 .setup으로 따로 만들었음. self.access_token=self.client.post(reverse(‘token_obtain_pair’),self.data).data[‘access’]
14.로그인 안했을 때 게시글 작성 테스트
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)
15.이미지 없는 게시글 작성 테스트
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(reponse.data[“message”],“글작성완료!”)
self.assertEqual(reponse.status_code, 200) #둘중 위에것도 사용가능
16.이미지 포함한 게시글 작성 테스트
1)임시이미지 만들기
from django.test.client import MULTIPART_CONTENT, encode_multipart, BOUNDARY
from PIL import Image
import tempfile
def get_temporary_image(temp_file):
size = (200, 200)
color = (255, 0, 0, 0)
image = Iamge.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”
image_file = get_temporary_image(temp.file)
image_file.seek(0) #이미지의 첫 번째 파일 받아오기
self.article_data[“image”] = image_file
2)전송하기
response = self.client.post(
path=reverse(“article_view”),
data=encode_multipart(data=self.article_data, boundry=BOUNDARY),
contetn_type = MULTIPART_CONTENT,
HTTP_AUTHORIZATION = f“Bearer{self.access_token}”
)
self.assertEqual(response.data[“message”],“글작성완료!”)
17.더미데이터를 위한 faker 사용
from faker import Faker
fake = Faker()
1)pip install Faker
2)이름 랜덤 출력
from faker import Faker
fake = Faker()
print(faker.name())
print(faker.first_name())
print(faker.last_name())
+)이름은 한국어 가능 Faker(“ko_KR”)
3)단어 만들기(비밀번호로 이용)
print(faker.word())
4)문장 만들기(게시글 제목)
print(faker.sentence())
5)긴글 만들기(게시글 내용)
print(faker.text())
18.article setuptestdata
class ArticleReadTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.faker = Faker()
cls.articles = [] #우선 빈리스트
for I in range(10): #10개의 게시글
cls.user = User.objects.create_user(cls.faker.name(),cls.faker.word())
cls.articles.append(Article.objects.create(title=cls.faker.sentence(),content=cls.faker.text(), user=cls.user))
#user>models.py에서 create_user 메소드 가져오기
19.get absolute url
class ArticleReadTest(APITestCase):
def test_get_article(self):
for article in self.articles:
url = article.get-absolute_url()
response = self.client.get(url)
serializer = ArticleSerializer(article).data
for key, value in serializer.items(): #items 메소드
*article> models.py
def get_absolute_url(self):
return reverse(‘article_detail_view’, kwargs={“pk”:self.pk})
20.dictionary의 item 메소드
my_dict = {“a”:“b”,“c”:“d”,“e”:“f”}
for key, value in my_dict.items():
print(key) > a, c, e
print(value) > b, d, f
21.테스트 완성
def test_get_article(self):
for article in self.articles:
url = article.get-absolute_url()
response = self.client.get(url)
serializer = ArticleSerializer(article).data
for key, value in serializer.items(): #key > title, value > sentence
self.assertEqual(response.data[key],value) #response.data에서 돌아온 데이터가 value값이 나오는지 확인
22.serializermethodfield로 아티클에서 유저네임 받아오기
-fk가 pk값인 id 값으로 잡혀 있음. 대신 username이 나오도록 바꾸기
*serializers.py
class ArticleSerializer(serializers.ModelSerializer):
user = serializers.SerializerMethodField()
def get_user(self, obj):
return obj.user.username
'스파르타코딩클럽[AI트랙 3기] > 장고' 카테고리의 다른 글
| [장고DRF]1,2주차(CRUD) (1) | 2022.11.14 |
|---|---|
| [장고심화]5주차 (0) | 2022.10.30 |
| [장고심화]4주차 (0) | 2022.10.28 |
| [장고심화]3주차 (0) | 2022.10.27 |
| [장고심화]2주차 (0) | 2022.10.26 |