<@classmethod>
- 클래스 내의 메소드 위에 @classmethod를 붙여주면 객체(인스턴스)를 생성함과 동시에 메소드를 실행할 수 있다
- @classmethod가 위에 붙는 메소드는 첫 번째 인자로 self 가 아닌 cls(클래스)가 붙는다
# 예제
from datetime import date
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 = Person("Sarah", 27)
person.display() # Sarah's age is 27
person1 = Person.fromBirthYear("Max", 1992)
person1.display() # Max's age is 31
<@staticmethod>
- @staticmethod가 위에 붙는 메소드는 인자에 self나 cls가 붙지 않는다 그래서 전역에 위치해도 상관이 없는데 해당 클래스 내에서 필요한 메소드인 경우 그 클래스 안에 넣어주기 위해 @staticmethod를 쓴다
<DRF로 테스트코드 작성하기>
- 로그인 테스트
- 일단 회원가입 테스트를 했던 클래스에서 이어서 로그인테스트 함수를 작성해서 실행하면 실패라고 뜬다
- 회원가입 테스트를 통해 만든 정보가 실제로는 DB에 담기지 않았기 때문이다
- 그래서 로그인이 필요한 API 테스트를 할 때는 setUp이라는 메소드를 사용해줘야 한다
- 일단 회원가입 테스트 클래스와 별개로 새로운 로그인 테스트 클래스를 만든다
# users/tests.py
...
class UserLoginTest(APITestCase):
def setUp(self):
self.data = {"email": "test@test.test", "password": "1234"}
self.user = User.objects.create_user("test@test.test", "1234")
def test_login(self):
response = self.client.post(reverse("token_obtain_pair"), self.data)
self.assertEqual(response.status_code, 200)
- self.data에는 로그인 정보를 담는다
- self.user에는 User 모델의 create_user 메소드를 이용해서 유저 객체 하나를 만들어 담는다
- test_login 함수에는 회원가입 테스트와 마찬가지로 클라이언트를 이용해서 post 요청을 보내면 돌아오는 응답을 response에 담는다
Found 2 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 1.492s
OK
Destroying test database for alias 'default'...
- 로그인 테스트가 성공한 것을 확인할 수 있다
- 참고로 test.py를 통해 test하는 건 우리가 작성한 코드에 대해서 test를 하는 것이다
- 장고에 내장 되어 있는 함수를 test 하진 않는다
- 사용자정보 가져오기 테스트
# users/tests.py
...
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("profile_view"),
HTTP_AUTHORIZATION=f"Bearer {access_token}"
)
print(response.data)
self.assertEqual(response.status_code, 200)
- 헤더에 사용자 정보를 걸어주기 위해 HTTP_AUTHORIZATION 변수에 엑세스토큰을 넣었다
- 근데 profile_view의 url에는 id가 들어가는데 강의에는 들어가지 않아서 id를 어떻게 넣는지 나와있지 않아서 에러가 뜬다
- 구글링 해보긴 했는데 뭐라 해야할지 모르겠어서 그냥 에러 난 채로 다음 강의로 pass...
Found 3 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E..
======================================================================
ERROR: test_get_user_data (users.tests.UserLoginTest.test_get_user_data)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\l\Desktop\sparta\drf_project\users\tests.py", line 31, in test_get_user_data
path=reverse("profile_view"),
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\l\Desktop\sparta\drf_project\venv\Lib\site-packages\django\urls\base.py", line 88, in reverse
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\l\Desktop\sparta\drf_project\venv\Lib\site-packages\django\urls\resolvers.py", line 828, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'profile_view' with no arguments not found. 1 pattern(s) tried: ['users/(?P<user_id>[0-9]+)/\\Z']
----------------------------------------------------------------------
Ran 3 tests in 2.095s
FAILED (errors=1)
Destroying test database for alias 'default'...
- 로그인 안 했을 때 게시글 작성 테스트
- 일단 views.py에서 게시글 작성 함수를 수정해야 한다
# articles/tests.py
...
class ArticleView(APIView):
...
def post(self, request):
"""게시글 작성"""
if not request.user.is_authenticated:
return Response({"message":"로그인 해주세요"}, status=status.HTTP_401_UNAUTHORIZED)
...
- 이 부분을 추가해서 로그인 안 했을 때 401 상태코드가 나오게 하자
# articles/tests.py
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from users.models import User
class ArticleCreateTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user_data = {"email":"test@test.test", "password":"1234"}
cls.article_data = {"title":"테스트제목", "content":"테스트내용"}
cls.user = User.objects.create_user("test@test.test", "1234")
def setUp(self):
self.access_token = self.client.post(reverse("token_obtain_pair"), self.user_data).data["access"]
- 일단 이렇게 작성하는데, @classmethod 아래에 있는 함수는 모든 함수가 실행되기 전에 먼저 실행되는 함수다
- 그리고 setUp 함수는 함수들이 실행될 때마다 그 함수보다 먼저 실행되는 함수다 각 객체로의 접근이 필요해서 따로 빠졌다
# articles/tests.py
...
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)
...
- 이렇게 하고 명령어를 입력하면 아래와 같은 결과가 나온다
(venv) C:\Users\l\Desktop\sparta\drf_project>python manage.py test articles
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.802s
OK
Destroying test database for alias 'default'...
- 현재 users앱에도 테스트 코드가 있기 때문에 articles 앱의 테스트코드만 실행하고 싶은 경우에는 python manage.py test 뒤에 앱이름을 붙여야 한다