问题描述
我想测试一个方法,无论它是否调用临时内部对象的特定方法.(ConfigParser.read)
I'd like to test a method, whether it calls a specific method of a temporary internal object or not. (ConfigParser.read)
所以对象是在内部创建的,方法退出后外部就无法访问了.
So the object is created inside, and it's not accessible from the outside after the method exits.
使用 python 2.7
Using python 2.7
在 foobar.py 中
In foobar.py
import ConfigParser
class FooBar:
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
do_some_stuff()
我想测试一下 config.read 是否被调用.
I'd like to test whether config.read was called.
据我所知,补丁装饰器就是为此而制作的,但不幸的是,测试用例接收到的 MagicMock 对象与内部创建的对象不同,我无法靠近方法内部的对象.
As I understand, the patch decorator was made for this, but unfortunately the MagicMock object the testcase receives is not the same that is created inside, and I can't get near the object that lives inside the method.
我是这样试的:
class TestFooBar(TestCase):
def setUp(self):
self.myfoobar = FooBar()
@mock.patch('foobar.ConfigParser')
def test_read(self,mock_foobar):
self.myfoobar.method("configuration.ini")
assert mock_foobar.called # THIS IS OKAY
assert mock_foobar.read.called # THIS FAILS
mock_foobar.read.assert_called_with("configuration.ini") # FAILS TOO
问题是:- mock_foobar 在 self.myfoobar.method 内部创建 ConfigReader 之前创建.- 调试时,mock_foobar 有关于先前调用的内部数据,但没有read"属性(用于模拟 read 方法的内部 MagicMock)
The problem is: - mock_foobar is created before the self.myfoobar.method creates the ConfigReader inside. - when debugging mock_foobar has internal data about the previous calls, but no "read" property (the inner MagicMock for mocking the read method)
当然一种方法是重构并给 .read() 或 init() 一个 ConfigReader 对象,但并不总是可以更改代码,我想掌握方法的内部对象,不接触被测模块.
Of course one way out is refactoring and giving the .read() or the init() a ConfigReader object, but it's not always possible to change the code, and I'd like to grasp the internal objects of the method without touching the module under test.
推荐答案
你离我很近!问题是您正在模拟该类,但随后您的测试检查 read() 是否在该模拟类上被调用 - 但您实际上希望 read() 在您调用该类时返回的实例上被调用.以下工作 - 我发现第二个测试比第一个更具可读性,但它们都有效:
You're so close! The issue is that you are mocking the class, but then your test checks that read() is called on that mock class - but you actually expect read() to be called on the instance that is returned when you call the class. The following works - I find the second test more readable than the first, but they both work:
import ConfigParser
from unittest import TestCase
from mock import create_autospec, patch, Mock
class FooBar(object):
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
class TestFooBar(TestCase):
def setUp(self):
self.myfoobar = FooBar()
@patch('ConfigParser.ConfigParser')
def test_method(self, config_parser_class_mock):
config_parser_mock = config_parser_class_mock.return_value
self.myfoobar.method("configuration.ini")
config_parser_class_mock.assert_called_once_with()
config_parser_mock.read.assert_called_once_with("configuration.ini")
def test_method_better(self):
config_parser_mock = create_autospec(ConfigParser.ConfigParser, instance=True)
config_parser_class_mock = Mock(return_value=config_parser_mock)
with patch('ConfigParser.ConfigParser', config_parser_class_mock):
self.myfoobar.method("configuration.ini")
config_parser_class_mock.assert_called_once_with()
config_parser_mock.read.assert_called_once_with("configuration.ini")
这篇关于Python 内部实体模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!