TIL DAY 36 || Python Unittest on Django, How to Mock data

TK·2021년 4월 10일
1

TIL

목록 보기
42/55

Kakao API 를 사용하여 requests.get 으로 사용자의 정보를 받아오는 view 를 unit test 해야했다. 하지만 unit test 는 서드파티 앱에 의존하지 않아야하고, 자체적으로 test 할 수 있어야 하기 때문에 실제로 요청을 보내면 안된다.

그래서 해당 요청을 mocking 하던 중 마주했던 어려움들을 어떻게 풀어갔는지 소개하려고 한다.

mock.patch 로 requests.get() 의 return_value 를 그냥 dict 로 했더니, 뒤에 오는 json() 에서
dict has no attribute json 라는 에러가 발생했다.
그래서 return_value 를 requests.Response() 로 바꿔보기로 했다.

Modifying requests.Response() object

with patch

requests.get 의 return_value 를
실제 requests.Response object 를 만들어 값을 변경해주는 방법을 사용했다.

왜냐면 views.py 코드에서 requests.get 의 attribute 인 json() 까지 mocking 해 줄 생각을 못했었기 때문이다.

어쨌든 그 생각을 하기 전에는 다음과 같은 과정을 거쳐서 문제를 해결했다.

실제로 requests.Response() 객체를 만든 뒤
._content attribute 에
mock_content dictionary type 객체를
bytes 객체로 변환해주면
requests.Response.json() 의 값이 dictionary type 의 mock_content 가 된다.

--> 이렇게 했을 때는 쓸데없이 실제 object 를 만들어서 조작해야되기 떄문에 1. 귀찮고 2. 그만큼 메모리를 낭비하게 된다.

다음 방법을 보자.

patch decorator

실제로 requests.Response() 객체 자체를 만들지 않고, requests.get.json() 자체의 return_value 를 mocking 하는 아주 간단한 방법이 있었다.

  1. mocking 할 모듈을 patch 데코레이터 인자로 넘겨줌

  2. 함수의 파라미터로 데코레이터 인자로 넘겨받은 mocking 할 모듈 object를 받음
    이 때 넘겨받은 인자를 print 해보면 name 이 get 인 MagicMock object 라는 것을 알 수 있다.
    <MagicMock name='get' id='140646286606096'>

  3. MagicMock object 의 return_value 값을 response 에 할당한다.
    이 때 response 를 print 해보면 name 이 get() 인 MagicMock object 로 변했다.
    <MagicMock name='get()' id='140369968892704'>

get 과 get() 의 차이다.

get 은 모듈 자체이고 get() 은 object 이다.

  • print(mocked_request.json.return_value) 를 해보면
    <MagicMock name='get.json()' id='140564181636624'>

  • print(mocked_request.return_value.json.return_value 를 해보면
    <MagicMock name='get().json()' id='140260556133904'>

우리가 mocking 해야 할 instance 는 다음과 같다.

response = requests.get(KAKAO_USERINFO_REQUEST_URL, headers=headers).json()
간략히 나타내면

requests.get().json() 이고, 이를 풀어보면
requests.Response().json() 이 된다.

설명이 길었지만, 핵심은

wrong way

이 방법이 아니라


  response = mocked_request
  response.json.return_value = mock_content        
        

right way

이 방법으로 해주어야 한다는 것이다.


  response = mocked_request.return_value
  response.json.return_value = mock_content        
        

이렇게 하면 성공적으로 mocking 이 된다.

profile
Backend Developer

0개의 댓글