[기업협업] 퀀텀AI -Day 22-

제갈창민·2022년 1월 18일
0

기업협업[퀀텀AI]

목록 보기
15/18

D

돌파구가 보이지 않는 테스트 코드 정복은 목적지를 수정하여 우선적으로 status_code 와 Object 단위에 대한 테스트만 먼저 완성하기로 했다. 다시 말해, 실제 출력되는 값이 아닌, .count() 메소드를 사용해서 생성이 되는지만 테스트 하기로 한 것이다. 테스트를 해야하는 API는 즐비했고 사수님 포함 우리가 너무 많은 시간을 투자했기 때문에 이 이상은 낭비 할 수 없었다.

먼저 깔끔하게 Git 정리를 하고 최신 버전으로 pull 을 받은 후 각자가 구현한 다른 API로 넘어가서 테스트 코드를 적용했다.
이때 push & pull 하는 과정에서 remote origin & upstream 에 대한 궁금증이 생겨서 알아보았었다. 이에 관한 것은 다음 포스팅에서 다루기로 한다.
아래는 완성된 테스트 코드 전문이다.

class SchoolGradesTestCase(APITestCase):
    
    def setUp(self):
        User = get_user_model()
        self.user = User.objects.create_user(username='test', password='Password!', is_staff=True)
        self.access = AccessToken.for_user(self.user)
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.access}')
        self.serializer = GradesSerializer
        school = School.objects.create(school_name='test')
        Grade.objects.create(school_id=school.id, grade="1등급")

    def test_schoolgrade_viewset(self):
        data = {
            "school_id": 1,
            "grade" : "1등급"
            "others": "texttexttext",
            "school_info": [
                {
                    "school_name": "test",
                }
            ]
        }
        
        patch_data = {
            "grade_id" : 1,
            "grade" : "2등급"
        }

        response = self.client.get('/grade/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(Grade.objects.count(), 1)
        self.assertEqual(Grade.objects.get().school_name, 'test')
        
        response = self.client.patch('/grade/1/', patch_data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        response = self.client.delete('/grade/1/', format='json')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

R

response 부분을 살펴보면, ('url', '(입력 데이터)', '(데이터의 형식)') 과 같은 형태로 되어있다. 그리고 테스트에 사용하려는 요청 메소드(get, post, patch, delete)에 따라 이 형태도 바뀔 수 있다. get의 경우에는 body가 없고, list 의 형태로 데이터를 요청하고 출력하기 때문에 입력 데이터와 데이터의 형식을 넣지 않아도 된다. 여담으로 format 같은 경우는 settings.py 에서 default 값을 지정해두고 사용하는 것도 가능하다. 물론, setting 을 건드릴때는 항상 동료들과 상의 후 결정해야하는 것도 잊지 말아야 한다.

response = self.client.get('/grade/')
※ 전체 리스트를 불러오는 get 요청

response = self.client.patch('/grade/1/', patch_data, format='json')
※ patch_data 를 받아서 값을 수정하는 patch 요청

F

format 의 종류에는 multipartjson 두 가지를 Django 에서 기본적으로 지원한다. 특히나 factory 를 사용할 경우, multipart 형식이 디폴트 값이기 때문에 json 으로 작업하고자 한다면 따로 지정해주어야 한다.

이전 테스트와 이번 테스트간의 다른점은 정참조하는 테이블에서 데이터를 추가로 가져오는 로직이 포함된 API를 테스트 하는 것이다. Grade 라는 테이블은 School 을 정참조 하고 있고 Serializer 에서 school_name 을 추가로 가져오는 로직이 구현되어 있다.

school = School.objects.create(school_name='test')
Grade.objects.create(school_id=school.id, grade="1등급")

setUp 에서 Grade 테이블의 FK 값에 해당하는 school_id 가 필요하게 때문에 School의 Object 를 먼저 생성해주고, Grade Object 를 생성해준다.

self.assertEqual(Grade.objects.get().school_name, 'test')

추가로 포함된 school_name 을 제대로 가져왔다면 school_name 으로 필터링을 해도 Grade 가 출력되어야 하는 테스트를 진행한다.

여기까지 테스트 코드를 마무리하고 모든 코드를 싹 정리한 뒤 PR을 올렸다.

TIL

format = multipart & json

  • multipart
    : 웹 클라이언트가 요청을 보낼 때, http 프로토콜의 바디 부분에 데이터를 여러 부분으로 나눠서 보내는 것. 웹 클라이언트가 서버에게 파일을 업로드할 때, http 프로토콜의 바디 부분에 파일정보를 담아서 전송을 하는데, 파일을 한번에 여러개 전송을 하면 body 부분에 파일이 여러개의 부분으로 연결되어 전송된다. 이렇게 여러 부분으로 나뉘어서 전송되는 것을 Multipart data라고 한다. 보통 파일을 전송할 때 사용한다.
    출처 : 코딩수첩 블로그

multipart vs json

  • application/json
    • 장점 : 파일과 함께 전달된 데이터의 연관 관계를 표현하기 용이하다.
    • 단점
      - 인코딩 방식의 특성으로 인해 바이너리 데이터보다 33-37 % 많은 용량을 차지한다.
      (base64 인코딩 방식이 인코딩 시 바이트 당 8 비트를 차지하는 바이너리 방식과 달리,
      6 비트를 차지하여 이론상 8/6 = 1.33, 약 33 % 많은 용량을 차지하지만 실제로는
      패딩 등의 이유로 3~4 % 더 차지함)
      - 서버는 디코딩, 클라이언트는 인코딩을 위한 프로세싱 오버헤드가 부가된다.
      - 인코딩한 파일 컨텐츠의 문자열이 길어져 서버측에서 파일을 읽지 못하는 경우가 발생할 수 있다.

  • multipart/form-data
    • 장점 : 파일 업로드 시 application/json 방식에서 발생하는 단점을 감수하지 않을 수 있다.
    • 단점 : 파일과 함께 전달된 데이터의 연관 관계 표현이 제한된다.

출처 : <Ryan (Geonhee) Son> 님의 벨로그

profile
자기계발 중인 신입 개발자

0개의 댓글