[기업협업] 퀀텀AI -Day 20~21-

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

기업협업[퀀텀AI]

목록 보기
14/18

!이번 포스팅의 코드들은 성공하지 못한 코드들임을 미리 밝힙니다!

D

Dictionary 의 다른 모습인 OrderedDict에 잡혀서 금요일에 이어 주말에도 문제 해결을 위한 노력은 계속 됐다.
완성된 샘플의 모양새에 맞추려고만 하다보니 오히려 생각이 갇혀버려서 마치 눈 앞의 벽만 보고서 이 길은 막혀있다고 단정짓는 모양새가 되어 버린듯 했다. 해서, 다른 방법들로 시도해보기로 마음을 바꿨다. 이번에 시도해볼 것은 APIRequestFactory 이다.

  • APIRequestFactory(정리글 펌)
    개발자 차원에서의 테스트. 단위 테스트 뷰를 함수단위로 테스트 하고 싶을 때 사용 한다. 장고는 웹 애플리케이션이 켜져 있고 사용자가 접속하기를 기다렸다가 요청에 대한 응답을 돌려 준다. 그래서 웹 서버만 켜져 있고 장고는 해당 요청에 대한 아웃풋만 주는 것. 웹 애플리케이션 이라는 것은 어떤 인풋이 들어왔을 때 아웃풋을 보내는 함수에 불과하다. APIRequestFactory는 뷰를 하나의 함수로 놓고 함수에 대해서 테스트를 할 수 있게 한다. API단위 자체를 함수로 구분 하는 것.
    request객체를 만들어 view(request)에 던지면 response 가 오는 형태인데, 이 view는 함수의 형태로 request를 받게 작성 되어 있기 때문에 해당 함수를 테스트 할 수 있게 된다. 그래서 하나 하나의 단위로 테스트 하고 싶을 경우 APIRequestFactory를 사용한다.
    출처: Django Restful framework Testing

R

RequestFactory는 Django 에서 지원하는 UnitTest 관련 모듈이다. 이에 대한 설명은 Django 공식문서에 잘(?) 나와있다.

The RequestFactory shares the same API as the test client. However, instead of behaving like a browser, the RequestFactory provides a way to generate a request instance that can be used as the first argument to any view. This means you can test a view function the same way as you would test any other function – as a black box, with exactly known inputs, testing for specific outputs.

The API for the RequestFactory is a slightly restricted subset of the test client API:

  • It only has access to the HTTP methods get(), post(), put(), delete(), head(), options(), and trace().
  • These methods accept all the same arguments except for follow. Since this is just a factory for producing requests, it’s up to you to handle the response.
  • It does not support middleware. Session and authentication attributes must be supplied by the test itself if required for the view to function properly.
    Django 공식문서

요약하자면, "RequestFactory는 요청 데이터를 생성해주는 공장이다, 정확히 알려진 입력을 사용하여 특정 출력을 테스트 한다" 정도가 되겠다.

F

framework 들이 대개 그렇듯, DRF도 Django 의 거의 모든 부분에서 확장된 기능을 제공하고 있다. APIRequestFactory 는 다음과 같이 설명된다.

The APIRequestFactory class supports an almost identical API to Django's standard RequestFactory class. This means that the standard .get(), .post(), .put(), .patch(), .delete(), .head() and .options() methods are all available.
DRF 공식문서

간단하게, "RequestFactory 가 할 수 있는건 거의 다 할 수 있습니다" 라는 뜻이다.

친절하게 git repo 까지 제공하고 있지만, 너무 어려워서 미간을 좁히던 중, 이전 포스팅에서 좀 더 쉬운 예제로 되어있는 repo의 링크가 있단걸 기억하고 열심히 참고해 보았다. 먼저 factories.py를 만들고 tests.py 로 넘어가야한다.
sp41mer/drf-test-examples

TIL

닉값 하는 진짜 심플한 APISimpleTestCase (doesn't work with DB)

factories.py
from factory.django import DjangoModelFactory

from .models    import School, Teacher

class SchoolFactory(DjangoModelFactory):
    class Meta:
        model = School

class TeacherFactory(DjangoModelFactory):
    class Meta:
        model = Teacher

tests.py
from django.contrib.auth.models import User
from django.contrib.auth 	import get_user_model
from django.urls 		import reverse

from rest_framework 		     import status
from rest_framework.test 	     import APIRequestFactory, APISimpleTestCase, APITestCase
from rest_framework.authtoken.models import Token

from apps 	import serializers, models
from .factories import SchoolFactory, TeacherFactory
from .views 	import SchoolViewSet

class TestCaseSchoolSimple(APISimpleTestCase):

    def test_create_school_request_factory(self):
        school = SchoolFactory.build(school_name='Test')
        
        self.assertEqual(school.school_name, 'Test')

설명에도 나와 있듯, 이 테스트는 DB 근처도 가지 않는다. 지정된 Factory class 에서 생성된 값을 곧바로 비교하는 원리이다.
도데체 이걸 어디다 써먹어야 되는지 잘 모르겠고, 짐작으로는 정말 간단한 200_OK 로직 같은 것을 테스트 할 때 사용 할 수 있을 것 같다. 당연하겠지만, build 값과 assertEqual 값이 다르면 테스트가 실패한다. 간단한 만큼 테스트 속도는 아주 빠르다.

APIRequestFactory, APITestCase 그리고 setUp

SimpleTest 로 기분좋게 출발했으니, 본론으로 가보자. 참고 Repo에 있는 코드를 잘 대입해서 get요청에 대한 테스트를 짜 보았다.

    def test_get_school_request_factory(self):
        school = SchoolFactory(name="Test")
        request_factory = APIRequestFactory()
        request = request_factory.get("/schools")
        view = SchoolViewSet.as_view({"get": "list"})
        response = view(request)
        self.assertEqual(response.status_code, status.HTTP_200_OK)

일단 결과는 OK, 그러나 잘 살펴보니 허점이 군데 군데 발견되었다.

  • 인증/인가에 대한 로직 없음
    : 지금까지 해왔던 테스트에선 항상 setUp을 만들어서 User를 생성하고, 인증을 fake로 통과시킨 Token도 생성시킨 뒤 테스트 함수가 작동되는 형태였다. 이 작업들이 없음에도 OK가 뜬 이유를 살펴보니, 나의 view에 permission_class가 빠져있었다. 또한, 참조 Repo 에도 설정이 되어있지 않았기 때문에 굳이 Token 이 없어도 로직이 작동 되었던 것이다.

  • Factory 를 쓰나, objects.create()를 쓰나 다른점이 무엇일까?
    : 일단 알아낸 것은 SchoolFactory() 괄호안에 아무것도 입력하지 않아도 model에 설정되어 있는 field 속성에 따라 빈 값들이 입력된 채로 Object 1개가 생성이 되는 것을 확인했다. .create()의 경우 빈 값으로 활용 할 수 없으므로 차이점이라고 할 수 있겠다.

OK가 떴으나, 전혀 신뢰가 가지 않는 테스트 코드이기 때문에 실패한 코드인 것이다.
Factory 에 대해 좀 더 깊게 알아볼 필요가 있겠다. 무언가 다른 방향으로 조금 더 활용도 높게 사용 할 수 있을 것 같은 느낌이다.

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

0개의 댓글