파이썬 단위 테스트에서 모의와 패치 통합
Aug 20 2020
단위 테스트 케이스를 작성하는 몇 가지 메서드가있는 클래스가 있습니다. 재현 가능한 최소 예제를 위해 해당 클래스의 메서드 중 3 개를 첨부합니다.
내가 테스트하는 클래스 :
class WebViewLincSession(object):
def renew_session_id(self, request):
session = request.getSession()
new_session_key = self.get_token()
while new_session_key in session.guard.sessions: # just in case the key is already used
new_session_key = self.get_token()
session.guard.sessions.pop(session.uid) # remove the current session
session.uid = new_session_key # update the key
session.guard.sessions[new_session_key] = session # add session back with the new key
request.addCookie(session.guard.cookieKey, new_session_key, path='/', secure=True, httpOnly=True) # send updated cookie value
def set_nonce(self, request):
'''
create a nonce value and send it as cookie
'''
if self._nonce_key is None:
if self._NONCE_FOR_TEST:
self._nonce_key = 'ecnon_for_test'
else:
self._nonce_key = 'ecnon_' + self.get_token()
new_nonce_value = self.get_token()
while new_nonce_value in self._nonce: # just in case the value is already used
new_nonce_value = self.get_token()
now = time()
stay_alive = now + self._STAY_ALIVE
# reset timeout value for all existing nonces
for key in self._nonce.keys():
if self._nonce[key] > stay_alive:
self._nonce[key] = stay_alive
self._nonce[new_nonce_value] = now + self._NONCE_TIMEOUT
request.addCookie(self._nonce_key, new_nonce_value, path='/', secure=True, httpOnly=True) # send updated cookie value
return new_nonce_value
def get_valid_nonce(self):
now = time()
return [nonce for nonce in self._nonce.keys() if self._nonce[nonce] > now]
내 테스트 클래스는 다음과 같습니다.
from __future__ import (division, absolute_import, with_statement)
from time import sleep
from mock import patch, MagicMock, mock, Mock
from requests.sessions import Session
from twisted.trial.unittest import TestCase
from viewlinc.webserver.web_viewlinc_session import WebViewLincSession
class MockGuard(object):
'''Mock guard object for testing'''
def __init__(self, *ags, **kwargs):
''' class constructor
'''
super(MockGuard, self).__init__(*ags, **kwargs)
self.cookieKey = 'test_cookie_key'
self.sessions = {'_test_session_': {}}
class MockSession(object):
'''Mock session object for testing'''
def __init__(self, *ags, **kwargs):
''' class constructor
'''
super(MockSession, self).__init__(*ags, **kwargs)
self.guard = MockGuard()
self.uid = '_test_session_'
class MockRequest(object):
'''Mock Request object for testing'''
def __init__(self, *ags, **kwargs):
''' class constructor
'''
super(MockRequest, self).__init__(*ags, **kwargs)
self.session = MockSession()
self.cookies = {}
def getSession(self):
''' returns session object
'''
return self.session
def addCookie(self, key, value, path='/', secure=True, httpOnly=True, expires=None):
''' add/replace cookie
'''
self.cookies[key] = {
'value': value,
'path': path,
'secure': secure,
'httpOnly': httpOnly,
'expires': expires
}
def getCookie(self, key):
''' retrieve a cookie
'''
cookie = self.cookies.get(key, {'value': None})
return cookie['value']
class WebViewLincSessionTests(TestCase):
'''Test WebViewLincSession methods'''
def __init__(self, *ags, **kwargs):
''' class constructor
'''
super(WebViewLincSessionTests, self).__init__(*ags, **kwargs)
self.request = MockRequest()
self.web_session = WebViewLincSession()
def test_02_renew_session_id(self):
'''Test renew_session_id
'''
self.web_session.renew_session_id(self.request)
session = self.request.session
return self.assertTrue(session.uid != '_test_session_' and session.uid in session.guard.sessions, 'renew_session_id failed')
def test_03_set_nonce(self):
'''Test set_nonce
'''
self.web_session.set_nonce(self.request)
return self.assertTrue(len(self.request.cookies) > 0, 'set_nonce failed.')
def test_04_get_valid_nonce(self):
'''Test get_valid_nonce
'''
# use a clean session
web_session = WebViewLincSession()
web_session.set_nonce(self.request)
web_session.set_nonce(self.request)
valid_nonce = web_session.get_valid_nonce()
self.assertTrue(len(valid_nonce) == 2, 'Expecting 2 valid nonces.')
sleep(16)
valid_nonce = web_session.get_valid_nonce()
return self.assertTrue(len(valid_nonce) == 1, 'Expecting 1 valid nonce.')
내가 원하는 것 :
가능한 한 내 테스트 클래스에서 mock / patch를 사용하고 싶습니다. 그것은 아마도 MockGuard
, MockSession
그리고 MockRequest
mock의 인스턴스로 대체 됨을 의미합니다 . unittest
파이썬의 패키지에서 모의 / 패치를 사용하도록 어떻게 다듬을 수 있는지보고 싶습니다 .
답변
1 MrBeanBremen Aug 20 2020 at 02:57
좋습니다. 아이디어를 제공하려고합니다. 테스트에서 테스트에 대한 가짜 addCookie
메서드를 만들었지 만 어떻게 addCookie
호출 되었는지 확인하는 데만 사용합니다 . 예를 들어 테스트 3과 4를 다시 작성할 수 있습니다.
def test_03_set_nonce(self):
request = mock.Mock()
self.web_session.set_nonce(request)
# we only need to know that it was called once
request.addCookie.assert_called_once()
def test_04_get_valid_nonce(self):
request = mock.Mock()
web_session = WebViewLincSession()
web_session.set_nonce(request)
web_session.set_nonce(request)
# check that addCookie it has been called twice
self.assertEqual(2, request.addCookie.call_count)
valid_nonce = web_session.get_valid_nonce()
... # the rest is not dependent on mocks
다른 테스트에서는 호출에 사용 된 인수를 확인해야 할 수도 있습니다. 항상 실제로 테스트 할 내용을 정의한 다음 해당 기능 만 테스트되도록 모의를 설정해야합니다.
또한 어떤 경우에는 당신이했던 것처럼 여분의 모의 클래스를 사용하는 것이 합리적 일 수 있습니다. 그것이 당신에게 가장 잘 작동한다면 그에 아무런 문제가 없습니다.