한 기업에서 내준 사전과제를 하다가 테스트코드를 알게 되었다.
django로 프로젝트를 시작하면 보통 앱과 같은 폴더에 tests.py로 생성되지만
여기 한 파일에 모든 테스트코드를 담기 어려우면 아래와 같이 폴더에서 나누어도 똑같이 동작한다.
DRF 테스트에서는 구현한 앱의 API 동작을 테스트할 수 있다.
우리가 내부서버를 실행시키고 브라우저에서 테스트하는 것을 대신 해주는 것이다.
아래의 테스트 코드 예시를 보자
class UserAPITestCase(APITestCase):
# 회원 가입
def test_registration(self):
register_uri= reverse("Todo:register")
user_data ={
'username':"이진욱",
"password":"1q2w3e4r!!",
"password2":"1q2w3e4r!!",
}
before = USER.objects.all().count()
response = self.client.post(register_uri, data=user_data)
after = USER.objects.all().count()
self.assertEqual(before+1,after)
self.assertEqual(response.status_code,204)
URI가 복잡해질 수 있어, 템플릿을 작성할때 사용하던 reverse
를 활용해주는 것이 좋았다.
(인자를 전달할때는 self.client2.put(reverse("Todo:task_detail", kwargs={'pk':task_id}),modified_data)
이런 방식으로 작성한다.)
테스트코드에서는 self.client.method
로 api를 테스트한다.
self.client
가 api를 보내는 사람에 해당한다고 생각하면 될 것 같다.
self.assertEqual(a,b)
는 a
, b
가 일치하는지 판단하여 일치하면 통과, 일치하지 않으면 테스트에서 에러를 발생시켜주는 함수다.
즉, DRF 테스트는 테스트에서 원하는 결과가 나오는지 assertEqual
함수를 통해 판단하여 테스트 성공, 실패를 판단하는 방식이다.
또한, 테스트 함수의 이름은 반드시 앞에 test_
가 붙어야 한다.
테스트 원칙에 따라 테스트는 각각 초기화된 상태로 진행한다.
아래의 예시를 보자
class DRFTestCase(APITestCase):
def test_A_Test(self):
tester = USER.objects.create(
username="name",
password="1q2w3e4r!!",
)
print(USER.objects.all())
self.assertEqual(1,1)
def test_B_Test(self):
print(USER.objects.all())
self.assertEqual(1,1)
A테스트에서 USER 인스턴스를 하나 생성했다.
그 뒤 B에서 USER DB를 불러왔다.
결과는 다음과 같다.
A테스트에서 생성한 유저 DB가 B테스트로 넘어가지 않는다.
테스트는 각각 독립적이여야하기 때문이다.
문제는 독립적이기 때문에 모든 테스트에서 같은 코드가 중복될 가능성이 높다.
유저 로그인이 필요한 API에선 각각의 테스트마다 유저 생성, 로그인을 반복해줘야 하기 때문이다.
이럴때 필요한 것이 setUp
함수이다.
setUp
함수는 테스트 클래스 맨 처음으로 오는 함수이며, 예외적으로 클래스 전체에 영향을 줄 수가 있다.
class DRFTestCase(APITestCase):
def setUp(self):
self.tester = USER.objects.create(
username="name",
password="1q2w3e4r!!",
)
print(USER.objects.all())
def test_A_Test(self):
print(USER.objects.all())
self.assertEqual(1,1)
def test_B_Test(self):
print(USER.objects.all())
self.assertEqual(1,1)
클래스에 setUp
함수를 추가하고 같은 테스트를 진행했다.
결과는 아래와 같다.
A테스트와 B테스트에도 유저 정보가 넘어갔다.
이런 식으로 setUp
함수를 활용하면 테스트코드 중복에서 오는 손실을 막을 수 있다.
특정 API는 접근에 권한이 필요하다.
테스트 코드에서는 APIClient()
를 활용하여 로그인 및 API 접근을 할 수 있다.
class TaskAPITestCase(APITestCase):
def setUp(self):
self.tester = USER.objects.create(
username="user1",
password="1q2w3e4r!!",
)
self.client = APIClient()
self.client.login(username='user1', password='1q2w3e4r!!')
self.client.force_authenticate(user=self.tester)
self.tester2 = USER.objects.create(
username="user2",
password="1q2w3e4r!!",
)
self.client2 = APIClient()
self.client2.login(username='user2', password='1q2w3e4r!!')
self.client2.force_authenticate(user=self.tester2)
# 업무 조회
def test_get_task(self):
uri = reverse('Todo:task')
response = self.client.get(uri)
self.assertEqual(response.status_code,200)
우리 대신 API를 사용하는APIClient
객체를 만들고 로그인(login) 및 권한 부여(force_authenticate)를 해준다.
그러고 API를 보낼때 self.client.method
이런 식으로 보내주면 된다.
(만약 client2
유저로 보내려고 하면 self.client2.method
라고 작성해준다.)
테스트 코드에 대해서는 사실 거의 모르고 있었는데, 기업 과제를 하다가 작성하게 되었다.
직접 작성해보니 코드의 양도 엄청나고, 에러나 엣지케이스를 테스트하기 편해 그 중요성을 깨닫게 되었다.