Python 内部实体模拟
Python internal entity mocking
我想测试一个方法,是否调用临时内部对象的特定方法。 (ConfigParser.read)
所以该对象是在内部创建的,方法退出后无法从外部访问。
使用 python 2.7
在foobar.py
import ConfigParser
class FooBar:
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
do_some_stuff()
我想测试一下是否调用了config.read。
据我所知,补丁装饰器是为此制作的,但不幸的是,测试用例接收到的 MagicMock 对象与内部创建的对象不同,我无法靠近方法内部的对象。
我这样试过:
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" 属性(用于模拟读取方法的内部 MagicMock)
当然,一种解决方法是重构并为 .read() 或 init() 提供一个 ConfigReader 对象,但并不总是可以更改代码,而且我希望在不接触被测模块的情况下掌握方法的内部对象。
你太接近了!问题是您正在模拟 class,但是随后您的测试检查是否在该模拟 class 上调用了 read() - 但您实际上希望在返回的实例上调用 read()当您调用 class 时。以下作品 - 我发现第二个测试比第一个更具可读性,但它们都有效:
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")
我想测试一个方法,是否调用临时内部对象的特定方法。 (ConfigParser.read)
所以该对象是在内部创建的,方法退出后无法从外部访问。
使用 python 2.7
在foobar.py
import ConfigParser
class FooBar:
def method(self, filename):
config=ConfigParser.ConfigParser()
config.read(filename)
do_some_stuff()
我想测试一下是否调用了config.read。
据我所知,补丁装饰器是为此制作的,但不幸的是,测试用例接收到的 MagicMock 对象与内部创建的对象不同,我无法靠近方法内部的对象。
我这样试过:
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" 属性(用于模拟读取方法的内部 MagicMock)
当然,一种解决方法是重构并为 .read() 或 init() 提供一个 ConfigReader 对象,但并不总是可以更改代码,而且我希望在不接触被测模块的情况下掌握方法的内部对象。
你太接近了!问题是您正在模拟 class,但是随后您的测试检查是否在该模拟 class 上调用了 read() - 但您实际上希望在返回的实例上调用 read()当您调用 class 时。以下作品 - 我发现第二个测试比第一个更具可读性,但它们都有效:
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")