如何解决在Python单元测试中集成模拟和补丁
我有一个带有一些我要为其编写单元测试用例的方法的类。对于最小的可重现示例,我附上了该类中的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,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,**kwargs):
''' class constructor
'''
super(MockSession,**kwargs)
self.guard = MockGuard()
self.uid = '_test_session_'
class MockRequest(object):
'''Mock Request object for testing'''
def __init__(self,**kwargs):
''' class constructor
'''
super(MockRequest,**kwargs)
self.session = MockSession()
self.cookies = {}
def getSession(self):
''' returns session object
'''
return self.session
def addCookie(self,key,value,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,**kwargs):
''' class constructor
'''
super(WebViewLincSessionTests,**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.')
我想要的:
我想尽可能在测试类中使用模拟/补丁。这可能意味着将MockGuard
,MockSession
和MockRequest
替换为模拟实例。我想看看如何改进它以使用python unittest
包中的模拟/补丁。
解决方法
好的,尝试给您一个主意。在测试中,您为测试创建了伪造的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
在其他测试中,您可能还必须检查调用中使用的参数。您始终必须定义实际要测试的内容,然后设置模拟,以便仅测试该功能。
还请注意,在某些情况下,像您一样使用额外的模拟类可能很有意义-如果最适合您,那没有什么错。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。