참고 블로그
1. 사전적 뜻 : 모조품
Mocking : 사전적 정의에 맞게 볼 때 유닛 테스트 시 외부에 의존(프론트엔드와의 통신 등) 부분을 '가짜로' 대체해서 해주는 기법. 즉 외부로부터 의존하지 않고 독립적으로 테스트가 가능한 기법
어떻게 불러올까?
>>> from unittest.mock import Mock, MagicMock
>>> from unittest.mock import Mock
>>> mock=Mock(return_value='Hello, Mock!')
>>> mock()
'Hello, Mock!'
__str__
과 같은 매직 메서드가 자동으로 모킹되지 않는다. 하지만 MagicMock은 불편함을 감수해주는 좋은 클래스다. 매직 메서드를 미리 알아서 모킹해주기 때문이다.>>> from unittest.mock import MagicMock
>>> mock = MagicMock()
>>> mock.__str__.return_value
"<MagicMock id='140231244167728'>"
>>> mock.__str__.return_value = "I'm a magic mock"
>>> str(mock)
"I'm a magic mock"
patch 데코레이터
모킹과 비슷하게 외부로부터 독립적으로 유닛 테스트를 진행할 수 있지만 큰 차이점은 데코레이터의 특정 범위 내에서만 모킹을 해주게 하는 점이 큰 차이점이다.
그럼 왜 쓸까? -> 플로우 이해
from unittest import TestCase, main
from unittest.mock import patch
def hello():
return "Hello!"
class TestMe(TestCase):
@patch("__main__.hello", return_value="Mock!")
def test_hello(self, mock_hello):
self.assertEqual(hello(), "Mock!")
self.assertIs(hello, mock_hello)
mock_hello.assert_called_once_with()
if __name__ == "__main__":
main()
원래 "Hello!"을 리턴하는 hello() 함수가 "Mock!"를 대신 리턴하도록 @patch() 데코레이터로 patching을 하고 있다.
@patch() 데코레이터를 사용하여 patching을 하게되면 mock객체를 테스트 메서드의 인자로 추가하게 되는데, 위 예제 코드에서 mock_hello가 이 mock객체의 매개변수명으로 쓰이고 있다.
첫번째 인자 : patching할 메서드를 package.module.Class.method 형태의 문자열로 받는다.
어려운 내용이다. 일단 내가 사용하였던 코드가 어떻게 적용되는지 보자.
import json
from django.test import TransactionTestCase, Client
# transationtTestCase를 사용한 이유 : 연속된 과정에서 나는 에러를 방지
from unittest.mock import patch, MagicMock
# unittest.mock 관련한 것 import
from user.models import User
# 필요한 것 import
class KakaoLoginTest(TransactionTestCase):
# fake 데이터 만들기
def setUp(self):
User.objects.create(
username = '안다민',
kakao_id = '1234567890',
email = 'damin0320@kakao.com'
)
def tearDown(self):
User.objects.all().delete()
# 없애기
@patch('user.views.requests')
def test_kakao_login_success(self, mocked_requests):
client = Client()
class MockedResponse:
def json(self):
return {
"id" : "1234567890",
"properties" : {
"nickname" : "안다민"
},
"kakao_account" : {
"email" : "damin0320@kakao.com"
}
}
# 비교 가능한 가짜 반응 클래스로 리턴
mocked_requests.get = MagicMock(return_value=MockedResponse())
# 가짜 데이터와의 송수신
header = {'HTTP_Authorization' : 'access_token'}
response = client.post('/user/signin', content_type='application/json', **header)
self.assertEqual(response.status_code, 200)
# 로그인 성공에 대한 리턴
def test_kakao_login_fail(self):
client = Client()
header = {'No_Authorizaeion' : '1234'}
response = client.post('/user/signin', content_type='application/json', **header)
self.assertEqual(response.status_code, 400)
# 로그인 실패 시 리턴
중간 중간 필요한 내용들이 어떻게 나오는지 print 해보면서 진행해야 한다. 유닛테스트를 자주 해주면서 익숙해지고 눈에 익어야 할 것 같다. 아직 감이 오진 않는 정도고 쓸 수 있다? 정도까지 인 듯.