【发布时间】:2016-11-15 10:46:26
【问题描述】:
我在使用函数和属性修补类时遇到了一些问题。
我正在使用的项目结构如下:
project
|- src
| |- logic
| | |- sub_logic
| | | | __init__.py
| | | | cache.py
| | | | manager.py
| | | __init__.py
|- test
| | test.py
我的缓存文件是这样的
class Cache(object):
def __init__(self, val):
self._val = val
@property
def Val(self):
return self._val
def other_function(self):
return False
管理器文件如下所示
from cache import Cache
class Manager(object):
def __init__(self):
self._cache = Cache(20)
def do_something(self):
if self._cache.Val != 20:
raise ValueError(u"Val is not 20")
return True
def do_something_else(self):
if self._cache.other_function():
raise ValueError(u"Something is True")
我尝试进行的测试如下:
from unittest import TestCase
from mock import PropertyMock, patch
from logic.sub_logic.manager import Manager
from logic.sub_logic.cache import Cache
class ManagerTestCase(TestCase):
def test_01_cache(self):
manager = Manager()
self.assertEqual(manager.do_something(), True)
@patch('logic.sub_logic.manager.Cache.Val', new_callable=PropertyMock)
def test_02_cache(self, property_mock):
property_mock.return_value = 20
manager = Manager()
self.assertEqual(manager.do_something(), True)
@patch('logic.sub_logic.manager.Cache', spec=Cache)
def test_03_cache(self, cache_mock):
cache_mock.other_function.return_value = True
manager = Manager()
with self.assertRaises(ValueError):
manager.do_something_else()
@patch('logic.sub_logic.manager.Cache', spec=Cache)
def test_04_cache(self, cache_mock):
cache_mock.other_function.return_value = True
cache_mock.Val = PropertyMock()
cache_mock.Val.return_value = 20
manager = Manager()
with self.assertRaises(ValueError):
manager.do_something_else()
self.assertEqual(manager.do_something(), True)
@patch('logic.sub_logic.manager.Cache.Val', new_callable=PropertyMock)
@patch('logic.sub_logic.manager.Cache', spec=Cache)
def test_05_cache(self, cache_mock, property_mock):
cache_mock.other_function.return_value = True
property_mock.return_value = 20
manager = Manager()
with self.assertRaises(ValueError):
manager.do_something_else()
self.assertEqual(manager.do_something(), True)
@patch('logic.sub_logic.manager.Cache', spec=Cache)
def test_06_cache(self, cache_mock):
cache_mock.other_function.return_value = True
cache_mock.Val = 20
manager = Manager()
with self.assertRaises(ValueError):
manager.do_something_else()
self.assertEqual(manager.do_something(), True)
问题是 test_04_cache 和 test_05_cache 不工作。 在调试测试时,提供的模拟参数与我预期的一样。但是 Manager 创建了一个 MagicMock,其中属性 Val 不是 PropertyMock 而是 MagicMock。
我在 PyCharm Debugger 中检查了 test_06_cache,它报告了以下内容:
cache_mock.Val = {int}20manager._cache.Val = {MagicMock}<MagicMock name='Cache().Val' id='61044848'>
我错过了什么吗?还是不可能?
【问题讨论】:
-
如果您要模拟缓存,为什么要关心它是否真的作为属性实现?只需设置
cache_mock.Val = 20。 -
你建议用
cache_mock.Val = 20替换cache_mock.Val = PropertyMock() cache_mock.Val.return_value = 20?我刚试过,好像不行。 -
在 test_05 中,您首先模拟 Cache.Val,然后模拟 Cache,它将整个对象替换为 MagicMock。这就是为什么在 test_05 中您将 Val 视为 MagicMock。
-
你能扩展一下“似乎不起作用”吗?我的观点是,在真正的
Cache中Val是一个属性这一事实与Manager无关,因此当您对后者进行单元测试时,您可以只使用常规属性。 -
你需要设置
cache_mock().Val- 注意你可以访问类,而不是实例。
标签: python python-2.7 unit-testing mocking