[英]Mocking two functions with patch for a unit test
I have a function I want to unit test contains calls two other functions.我有一个 function 我想单元测试包含调用另外两个函数。 I am unsure how can I mock both functions at the same time properly using patch.我不确定如何使用补丁同时正确地模拟这两个功能。 I have provided an example of what I mean below.我在下面提供了一个例子来说明我的意思。 When I run nosetests, the tests pass but I feel that there must be a cleaner way to do this and I do not really Understand the piece regarding f.close()...当我运行 nosetests 时,测试通过了,但我觉得必须有一种更简洁的方法来做到这一点,我并不真正理解关于 f.close() 的文章......
The directory structure looks like this:目录结构如下所示:
program/
program/
data.py
tests/
data_test.py
data.py:数据.py:
import cPickle
def write_out(file_path, data):
f = open(file_path, 'wb')
cPickle.dump(data, f)
f.close()
data_test.py:数据测试.py:
from mock import MagicMock, patch
def test_write_out():
path = '~/collection'
mock_open = MagicMock()
mock_pickle = MagicMock()
f_mock = MagicMock()
with patch('__builtin__.open', mock_open):
f = mock_open.return_value
f.method.return_value = path
with patch('cPickle.dump', mock_pickle):
write_out(path, 'data')
mock_open.assert_called_once_with('~/collection', 'wb')
f.close.assert_any_call()
mock_pickle.assert_called_once_with('data', f)
Results:结果:
$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.008s
OK
You can simplify your test by using the patch decorator and nesting them like so (they are MagicMock
objects by default): 您可以使用修补程序装饰器简化测试并将其嵌套(默认情况下它们是MagicMock
对象):
@patch('cPickle.dump')
@patch('__builtin__.open')
def test_write_out(mock_open, mock_pickle):
path = '~/collection'
f = mock_open.return_value
f.method.return_value = path
write_out(path, 'data')
mock_open.assert_called_once_with('~/collection', 'wb')
mock_pickle.assert_called_once_with('data', f)
f.close.assert_any_call()
Calls to a MagicMock
instance return a new MagicMock
instance, so you can check that the returned value was called just like any other mocked object. 对MagicMock
实例的调用返回一个新的MagicMock
实例,因此您可以检查返回的值是否像任何其他模拟对象一样被调用。 In this case f
is a MagicMock
named 'open()'
(try printing f
). 在这种情况下, f
是名为'open()'
的MagicMock
(尝试打印f
)。
In addition to the response @Matti John you can also use patch
inside function test_write_out
: 除了响应@Matti John之外,您还可以在函数test_write_out
使用patch
:
from mock import MagicMock, patch
def test_write_out():
path = '~/collection'
with patch('__builtin__.open') as mock_open, \
patch('cPickle.dump') as mock_pickle:
f = mock_open.return_value
...
As of Python 3.10 you can do use Parenthesized Context Managers like this从 Python 3.10 开始,您可以像这样使用带括号的上下文管理器
from unittest.mock import patch
def test_write_out():
with (
patch('cPickle.dump'),
patch('__builtin__.open') as open_mock, # example of using `as`
):
yield
Here's a simple example on how to test raising ConflictError
in create_collection
function using mock: 这是一个关于如何使用mock在create_collection
函数中测试引发ConflictError
的简单示例:
import os
from unittest import TestCase
from mock import patch
from ..program.data import ConflictError, create_collection
class TestCreateCollection(TestCase):
def test_path_exists(self):
with patch.object(os.path, 'exists') as mock_method:
mock_method.return_value = True
self.assertRaises(ConflictError, create_collection, 'test')
Please, also see mock docs and Michael Foord's awesome introduction to mock . 请参阅模拟文档和Michael Foord 对模拟的精彩介绍 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.