본문 바로가기
Django

[Django] DRF - 1차 프로젝트 리팩토링 (4) API Testing

by 혀넝 2022. 6. 14.

API 부분의 리팩토링이 어느 정도 끝난 후 test code를 작성했다. 

1. Category & Product

먼저 category와 product의 detail과 list를 get에 관련한 테스트 코드를 작성했다.

# category

class CategoryTestCase(APITestCase):
    def setUp(self):
        self.category = Category.objects.create(
                                    category_name    = 'test category',
                                    main_description = 'test main description',
                                    sub_description  = 'test sub description'
                                )

    def test_category_list_get(self):
        response = self.client.get(reverse('category-list'))
        self.assertEqual(response.status_code, 200)
    
    def test_category_detail_get(self):
        response = self.client.get(reverse('category-detail', args=(self.category.id, )))
        self.assertEqual(response.status_code, 200)
        


# product

class ProductTestCase(APITestCase):
    def setUp(self):
        self.category = Category.objects.create(
                                    category_name    = 'test category',
                                    main_description = 'test main description',
                                    sub_description  = 'test sub description'
                                )

        self.feeling    = Feeling.objects.create(name='test feeling')
        self.skin_type  = SkinType.objects.create(name='test skin type')
        self.ingredient = Ingredient.objects.create(name='test ingredient')

        self.product = Product.objects.create(
            name        = 'test name',
            price       = 1000.00,
            size        = 'test size',
            description = 'test description',
            category    = self.category,
            howtouse    = {'test':'test'},
            badge       = 'test badge'
        )

    def test_product_list_get(self):
        response = self.client.get(reverse('product-list'))
        self.assertEqual(response.status_code, 200)
    
    def test_product_detail_get(self):
        response = self.client.get(reverse('product-detail', args=(self.product.id, )))
        self.assertEqual(response.status_code, 200)

detail get의 경우, url에서 <int:pk> 부분이 있어 id를 넘기는 부분이 필요했고, 때문에 reverse 안에 args를 설정했다. 여기서 id를 가져오기 위해서 setUp 부분에서 object를 한 개씩 만들어 주었다.

 

2. Review

Review의 경우, view에서 permission_classes = [IsAuthenticated]로 설정되어 있는 경우가 많아 이 부분을 해결하는데 오랜 시간이 걸렸다.

내가 계속 마주한 에러로, 

django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails ….

위와 같은 에러가 있었는데, 알고 보니 내가 model에서 기존에 만들어 둔 User에서 drf에서 제공하는 auth.model의 User로 바꾸고 makemigrations을 하지 않아서 발생한 에러였다. migrate까지 진행하지 잘 해결되었다.

또한 알게 된 점이 있다면, foreign key로 물려있는 부분은 ‘category=self.category’와 같이, 위에서 만든 객체를 가지고 와야 했지만 many to many field로 엮여 있는 부분은 객체를 생성한 하면 되고 product create 안에서 위에서 만든 객체를 가지고 올 필요가 없었다.

class ReviewTestCase(APITestCase):
    def setUp(self):
        self.user = User.objects.create_user(username='example', password='Password123!')
        refresh   = RefreshToken.for_user(self.user)
        self.client.credentials(HTTP_AUTHORIZATION='Bearer {0}'.format(refresh.access_token))

        self.category = Category.objects.create(
                                    category_name    = 'test category',
                                    main_description = 'test main description',
                                    sub_description  = 'test sub description'
                                )

        self.feeling    = Feeling.objects.create(name='test feeling')
        self.skin_type  = SkinType.objects.create(name='test skin type')
        self.ingredient = Ingredient.objects.create(name='test ingredient')

        self.product = Product.objects.create(
            name        = 'test name',
            price       = 1000.00,
            size        = 'test size',
            description = 'test description',
            category    = self.category,
            howtouse    = {'test':'test'},
            badge       = 'test badge'
        )
        
        self.review = Review.objects.create(
                                user    = self.user,
                                product = self.product,
                                content = 'test content'
                            )

    def test_reveiw_list_get(self):
        response = self.client.get(reverse('review-list', args=(self.product.id, )))
        self.assertEqual(response.status_code, 200)

    def test_review_detail_get(self):
        response = self.client.get(reverse('review-detail', args=(self.review.id, )))
        self.assertEqual(response.status_code, 200)

 

review create에 관한 test의 경우, 이미 첫 번째 user는 리뷰를 작성한 것처럼 되어 있기 때문에 user를 하나 더 생성해서 진행했다. 그렇지 않고 첫 번째 user를 그대로 사용하면, “your review for this product already exists”라고 하는 error가 발생한다.

class ReviewTestCase(APITestCase):
    def setUp(self):
        self.user = User.objects.create_user(username='example', password='Password123!')
        refresh   = RefreshToken.for_user(self.user)
        self.client.credentials(HTTP_AUTHORIZATION='Bearer {0}'.format(refresh.access_token))

        self.user_two = User.objects.create_user(username='example2', password='Password123!')
        refresh_two   = RefreshToken.for_user(self.user_two)
        self.client.credentials(HTTP_AUTHORIZATION='Bearer {0}'.format(refresh_two.access_token))

....

    def test_review_create(self):
        data = {
            "user"   : self.user_two,
            "product": self.product,
            "content": "test content"
        }
        response = self.client.post(reverse('review-create', args=(self.product.id, )), data)
        self.assertEqual(response.status_code, 201)