关于单元测试:如何使用python模拟库和decorator与unittest lib?

How to use python mock library and decorator with unittest lib?

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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"调用的顺序,则以下补丁装饰器将起作用。

1
2
3
4
5
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)

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