簡體   English   中英

在 python 單元測試中集成模擬和補丁

[英]integrating mock and patch in a python unit test

我有一個 class 和一些我正在為其編寫單元測試用例的方法。 對於最小的可重復示例,我附上了 class 中的 3 種方法:

Class 我正在測試的方法:

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]

我的測試 class 如下所示:

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.')

我想要的是:

我想盡可能在我的測試 class 中使用模擬/補丁。 這可能意味着MockGuardMockSessionMockRequest被替換為模擬實例。 我想看看如何改進它以使用 python 中的unittest package 中的模擬/補丁。

好的,試着給你一個想法。 在測試中,您為測試創建了一個虛假的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

在其他測試中,您可能還需要檢查調用中使用的 arguments。 你總是必須定義你真正想要測試的東西,然后設置你的模擬,以便只測試那個功能。

另請注意,在某些情況下,像您所做的那樣使用額外的模擬類可能是有意義的 - 如果這對您最有效,那沒有任何問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM