[DRF TEST]

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’) #modeldef create_user를 씀. usernamepassword 받아줌.

 

 

 

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

 

selfclass가 안들어감. 굳이 안에 쓰는 것은 그냥 class 안에서 정의해주고 사용하게끔하는 것(편의를 위해 넣어둔 것). 반면 classmethod는 반드시 거기에 써줘야함.

 

13.다시 setuptestdata

setupdataclass안에 넣어줌.

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): #clientclassmethod아니기 때문에 .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.dictionaryitem 메소드

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로 아티클에서 유저네임 받아오기

-fkpk값인 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