개발일지/Today I Learned

[Django] 최종 프로젝트 : 지금은 전시상황!(3) - Accompanies 앱 테스트 코드 작성

마이구미+ 2023. 6. 9. 21:47

<AccompanyView>

- 동행 구하기 댓글 작성 테스트

# accompanies/tests.py

from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from users.models import User
from accompanies.models import Accompany
from exhibitions.models import Exhibition


# ---------------------------동행 구하기 댓글 CRUD 테스트------------------------
class AccompanyViewTest(APITestCase):
    # ----------------유저, 전시회, 동행 구하기 댓글 데이터 생성---------------
    @classmethod
    def setUpTestData(cls):
        cls.user_data = {
            "email": "test@test.com",
            "nickname": "testuser",
            "password": "123",
        }
        cls.exhibition_data = {
            "info_name": "Test Info_name",
            "content": "Test Exhibition Content",
            "location": "Test Location",
            "category": "Test Category",
            "start_date": "2022-06-04",
            "end_date": "2022-06-10",
        }
        cls.accompany_data = {
            "content": "Test Accompany Content",
            "personnel": 3,
            "start_time": "2023-06-13 11:00",
            "end_time": "2023-06-13 15:00",
        }
        cls.user = User.objects.create_user(**cls.user_data)
        cls.exhibition = Exhibition.objects.create(**cls.exhibition_data, user=cls.user)

    def setUp(self):
        self.access_token = self.client.post(
            reverse("users:user_signin"), self.user_data
        ).data["access"]

    # --------------동행 구하기 댓글 작성 테스트------------------------
    def test_create_accompany(self):
        response = self.client.post(
            path=reverse(
                "accompanies:accompany_view",
                kwargs={"exhibition_id": self.exhibition.id},
            ),
            data=self.accompany_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )
        print(response)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Accompany.objects.count(), 1)
        self.assertEqual(
            Accompany.objects.get().content, self.accompany_data["content"]
        )
  • 다른 팀의 레파지토리를 참고해 테스트코드를 작성해봤다
ERROR: test_create_accompany (accompanies.tests.AccompanyViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\l\Desktop\Projects\05-Final\AI_5-B4-Exhibitions-Backend\.venv\lib\site-packages\django\urls\base.py", line 71, in reverse
    extra, resolver = resolver.namespace_dict[ns]
KeyError: 'users'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\l\Desktop\Projects\05-Final\AI_5-B4-Exhibitions-Backend\accompanies\tests.py", line 45, in setUp
    reverse("users:user_signin"), self.user_data
  File "C:\Users\l\Desktop\Projects\05-Final\AI_5-B4-Exhibitions-Backend\.venv\lib\site-packages\django\urls\base.py", line 82, in reverse
    raise NoReverseMatch("%s is not a registered namespace" % key)
django.urls.exceptions.NoReverseMatch: 'users' is not a registered namespace
  • 이런 에러가 떴다
  • 45번째 줄에 users가 문제였다
  • settings.py 파일이 있는 urls.py에 적은 url을 써야 하나 해서 api/users로 바꿔보았지만 똑같은 에러가 떴다
  • 보니까 테스트코드 강의에서는 그냥 url의 name만 적었는데 내가 참고한 팀은 앞에 app_name을 붙여준 것이었다
  • url name이 겹칠까봐 그런건가..?
  • 여튼 코드를 쭉 보니까 각 앱들의 urls.py 파일에 app_name = "user" 이런 식으로 선언되어 있길래 나도 그렇게 했다
  • 각 앱마다 앱 이름을 지정해줬다
# accompanies/urls.py
...
app_name = "accompanies"
...
# users/urls.py
...
app_name = "users"
...
  • 이렇게 설정 후 테스트코드를 돌리니 OK 싸인이 떨어졌다..!!!

- 동행 구하기 댓글 조회 테스트

# accompanies/tests.py
...
    def test_accompany_list(self):
        self.accompanies = []
        for _ in range(5):
            self.accompanies.append(
                Accompany.objects.create(
                    content="Test Accompany Content",
                    personnel=3,
                    start_time="2023-06-13 11:00",
                    end_time="2023-06-13 15:00",
                    exhibition=self.exhibition,
                    user=self.user,
                )
            )
        response = self.client.get(
            path=reverse(
                "accompanies:accompany_view",
                kwargs={"exhibition_id": self.exhibition.id},
            ),
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Accompany.objects.count(), 5)
        self.assertEqual(len(response.data), 5)
        self.assertEqual(response.data[0]["content"], "Test Accompany Content")
  • 위에 이어서 작성 테스트 바로 아래에 작성했다
  • 25번째 줄에서 에러가 난다 response.data 길이는 2라고 나온다
  • response.data에 뭐가 들어오나 print문을 찍어봤다
{'message': '조회를 성공하셨습니다.', 
'data': [OrderedDict([('id', 1), ('applies', []), ('content', 'Test Accompany Content'), 
('personnel', 3), ('start_time', '2023-06-13T11:00:00'), ('end_time', '2023-06-13T15:00:00'), 
('created_at', '2023-06-09T16:03:12.366268'), ('updated_at', '2023-06-09T16:03:12.366268'), 
('user', 1), ('exhibition', 1)]), 
OrderedDict([('id', 2), ('applies', []), ('content', 
'Test Accompany Content'), ('personnel', 3), ('start_time', '2023-06-13T11:00:00'), ('end_time', 
'2023-06-13T15:00:00'), ('created_at', '2023-06-09T16:03:12.366268'), ('updated_at', 
'2023-06-09T16:03:12.366268'), ('user', 1), ('exhibition', 1)]), 
OrderedDict([('id', 3), 
('applies', []), ('content', 'Test Accompany Content'), ('personnel', 3), ('start_time', 
'2023-06-13T11:00:00'), ('end_time', '2023-06-13T15:00:00'), ('created_at', 
'2023-06-09T16:03:12.367271'), ('updated_at', '2023-06-09T16:03:12.367271'), ('user', 1), 
('exhibition', 1)]), 
OrderedDict([('id', 4), ('applies', []), ('content', 
'Test Accompany Content'), ('personnel', 3), ('start_time', '2023-06-13T11:00:00'), 
('end_time', '2023-06-13T15:00:00'), ('created_at', '2023-06-09T16:03:12.367271'), 
('updated_at', '2023-06-09T16:03:12.367271'), ('user', 1), ('exhibition', 1)]), 
OrderedDict([('id', 5), ('applies', []), ('content', 'Test Accompany Content'), 
('personnel', 3), ('start_time', '2023-06-13T11:00:00'), ('end_time', '2023-06-13T15:00:00'), 
('created_at', '2023-06-09T16:03:12.367271'), ('updated_at', '2023-06-09T16:03:12.367271'), 
('user', 1), ('exhibition', 1)])]}
F<Response status_code=201, "application/json">
.
======================================================================
FAIL: test_accompany_list (accompanies.tests.AccompanyViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\l\Desktop\Projects\05-Final\AI_5-B4-Exhibitions-Backend\accompanies\tests.py", line 89, in test_accompany_list
    self.assertEqual(len(response.data), 5)
AssertionError: 2 != 5
  • 보니까 데이터는 5개 잘 만들어졌고(24번째 줄 통과하고 25번째 줄에서 에러가 떴으면 당연한 얘기다) Response가 message랑 data로 이루어져 있는데 response.data는 이걸 세어서 그런 것 같다

  • 내 코드에서 response.data의 개수는 message 1개, data 1개 해서 총 2개이기 때문에 5와 달라서 에러가 뜬다
        self.assertEqual(len(response.data["data"]), 5)
  • 25번째 줄을 이렇게 변경하고 다시 테스트를 실행하니 이제 그 다음 줄에서 에러가 난다
ERROR: test_accompany_list (accompanies.tests.AccompanyViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\l\Desktop\Projects\05-Final\AI_5-B4-Exhibitions-Backend\accompanies\tests.py", line 90, in test_accompany_list
    self.assertEqual(response.data[0]["content"], "Test Accompany Content")
KeyError: 0
  • 26번째 줄도 같은 이유로 에러가 난 것이다
        self.assertEqual(response.data["data"][0]["content"], "Test Accompany Content")
  • 이렇게 수정해주니 테스트를 잘 통과한다!

- 동행 구하기 댓글 수정 테스트

# accompanies/tests.py
...
    def test_accompany_detail_update(self):
        self.accompany = Accompany.objects.create(
            **self.accompany_data, user=self.user, exhibition=self.exhibition
        )
        self.accompany_updated_data = {
            "content": "Updated Test Content",
            "personnel": 4,
            "start_time": "2023-06-15 10:00",
            "end_time": "2023-06-15 12:00",
        }

        response = self.client.put(
            path=reverse("accompanies:accompany_view", kwargs={"accompany_id": 1}),
            data=self.accompany_updated_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Accompany.objects.count(), 1)
        self.assertEqual(response.data["data"]["content"], "Updated Test Content")
        self.assertEqual(response.data["data"]["personnel"], 4)
        self.assertEqual(response.data["data"]["start_time"], "2023-06-15T10:00:00")
        self.assertEqual(response.data["data"]["end_time"], "2023-06-15T12:00:00")
  • 위에서 setUpTestData 함수에서 정의해둔 accompany_data로 accompany 객체를 만들고 accompany_updated_data에는 수정할 내용을 담는다
  • 부분 수정이 가능하므로 전부 수정해도 되고 1개든 2개든 원하는 대로 수정 가능하다(수정 안 하는 부분은 주석 처리)
  • test에서 오류가 없으려면 updated_data에 주석처리 한 부분이 있으면 그대로 맨 아래 assertEqual도 맞춰줘야 한다

- 동행 구하기 댓글 삭제 테스트

# accompanies/tests.py
...
    def test_accompany_detail_delete(self):
        self.accompany = Accompany.objects.create(
            **self.accompany_data, user=self.user, exhibition=self.exhibition
        )

        response = self.client.delete(
            path=reverse("accompanies:accompany_view", kwargs={"accompany_id": 1}),
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Accompany.objects.count(), 0)
        self.assertEqual(response.data, {"message": "동행 구하기 글이 삭제되었습니다."})

<ApplyView>

- 동행 신청하기 댓글 작성 테스트

# accompanies/tests.py

...
from accompanies.models import Apply
...


# ---------------------------동행 신청하기 댓글 CRUD 테스트------------------------
class ApplyViewTest(APITestCase):
    # ----------------유저, 동행 구하기/신청하기 댓글 데이터 생성---------------
    @classmethod
    def setUpTestData(cls):
        cls.user_data = {
            "email": "test@test.com",
            "nickname": "testuser",
            "password": "123",
        }
        cls.exhibition_data = {
            "info_name": "Test Info_name",
            "content": "Test Exhibition Content",
            "location": "Test Location",
            "category": "Test Category",
            "start_date": "2022-06-04",
            "end_date": "2022-06-10",
        }
        cls.accompany_data = {
            "content": "Test Accompany Content",
            "personnel": 3,
            "start_time": "2023-06-13 11:00",
            "end_time": "2023-06-13 15:00",
        }
        cls.apply_data = {
            "content": "Test Accompany Content",
        }
        cls.user = User.objects.create_user(**cls.user_data)
        cls.exhibition = Exhibition.objects.create(**cls.exhibition_data, user=cls.user)
        cls.accompany = Accompany.objects.create(
            **cls.accompany_data, user=cls.user, exhibition=cls.exhibition
        )

    def setUp(self):
        self.access_token = self.client.post(
            reverse("users:user_signin"), self.user_data
        ).data["access"]

    # --------------동행 신청하기 댓글 작성 테스트------------------------
    def test_create_apply(self):
        response = self.client.post(
            path=reverse(
                "accompanies:apply_view",
                kwargs={"accompany_id": self.accompany.id},
            ),
            data=self.apply_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )
        print(response)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Apply.objects.count(), 1)
        self.assertEqual(Apply.objects.get().content, self.accompany_data["content"])

- 동행 신청하기 댓글 수정 테스트

# accompanies/tests.py

...
    # --------------동행 신청하기 댓글 수정 테스트------------------------
    def test_apply_detail_update(self):
        self.apply = Apply.objects.create(
            **self.apply_data, user=self.user, accompany=self.accompany
        )
        self.apply_updated_data = {"content": "Updated Test Content"}

        response = self.client.put(
            path=reverse("accompanies:apply_view", kwargs={"apply_id": 1}),
            data=self.apply_updated_data,
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Accompany.objects.count(), 1)
        self.assertEqual(response.data["data"]["content"], "Updated Test Content")

- 동행 신청하기 댓글 삭제 테스트

# accompanies/tests.py

...
    # --------------동행 신청하기 댓글 삭제 테스트------------------------
    def test_apply_detail_delete(self):
        self.apply = Apply.objects.create(
            **self.apply_data, user=self.user, accompany=self.accompany
        )

        response = self.client.delete(
            path=reverse("accompanies:apply_view", kwargs={"apply_id": 1}),
            HTTP_AUTHORIZATION=f"Bearer {self.access_token}",
        )

        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Apply.objects.count(), 0)
        self.assertEqual(response.data, {"message": "동행 신청하기 댓글이 삭제되었습니다."})