如何使用python模拟库和decorator与unittest lib?

时间:2012-09-07 09:15:23

标签: python unit-testing mocking decorator

我正在尝试使用模拟python库,并决定使用装饰器来隐藏一些重复操作,以便使用相应的替换方法设置模拟side_effect变量。

到目前为止,我有以下代码,它没有进入测试,它基本上什么也没做。有想法该怎么解决这个吗?谢谢!

import unittest
from mock import patch

# Replacement method for requests.get call
def mock_requests_get(url=None, **kwargs):
    if url == URL1:
        return {'url':url, 'status_code':200, 'status':'success'}

    if url == URL2: A
        return {'url':url, 'status_code':403}

# Replacement method for requests.post call
def mock_requests_post(url, data=None, **kwargs):
    if url == URL1 and data['data']=='go':
        return {'url':url, 'status_code':200, 'status':'success'}

    if url == URL2 and data['data']!='gogo':
        return {'url':url, 'status_code':403}

# Decorator which sets mock replacement methods
def mock_type(method=''):
    def _mock(func):
        def _decorator(mock_get, mock_post, *args, **kwargs):
            print method
            if method == 'GET':
                mock_get.side_effect = mock_requests_get
            if method == 'POST':
                mock_post.side_effect = mock_requests_post
            func(mock_get, mock_post, *args, **kwargs)
        return _decorator
    return _mock

@patch('requests.post')
@patch('requests.get')
class TestKeywordsApi(unittest.TestCase):

    def setUp(self):
        self.ka = KeywordsApi()

    @mock_type('GET')
    def test_get(self, mock_get, mock_post):
        # Replace this code in mock_type decorator:
        #mock_get.side_effect=mock_requests_get

        print self.ka.get(URL1)
        print self.ka.get(URL2)

        # Do asserts

    @mock_type('POST')
    def test_post(self, mock_get, mock_post):
        # Replace this code in mock_type decorator:
        #mock_post.side_effect=mock_requests_post

        print self.ka.post(URL1, {'data':'go'})
        print self.ka.post(URL2, {'data':'go'})

        # Do asserts

1 个答案:

答案 0 :(得分:2)

确保替换执行命名空间中的函数。根据导入,您当前的代码可能会或可能不会替换您认为它正在替换的内容。以下是我认为您试图做的事情。

import kwmodule
import unittest, mock

def mock_requests_get(url=None, **kwargs):
    "Replacement method for requests.get call"
    pass

def mock_requests_post(url, data=None, **kwargs):
    "Replacement method for requests.post call"
    pass

@mock.patch('kwmodule.requests.post', mock_requests_post)
@mock.patch('kwmodule.requests.get', mock_requests_get)    
class TestKeywordsApi(unittest.TestCase):
     def setUp(self):
         self.ka = kwmodule.KeywordsApi()

然而,您可能更成功地更换了get&发布自动指定的MagicMock对象。如果这对您不起作用,使用您自己的自定义替换。

例如,如果您知道调用“get。”的顺序,则以下补丁装饰器将起作用。

return_values = [{'url':url, 'status_code':200, 'status':'success'}, 
                 {'url':url, 'status_code':403}, 
                 AssertionError('Unexpected call.')]

@mock.patch('kwmodule.requests.get', autospec=True, side_effect=return_values)

这将在第一次调用时返回“success”条件,第二次返回错误,如果第三次调用它将引发AssertionError。十分之九,我使用side_effect而不是编写自己的返回生成函数。