我在弄清楚如何使用side_effect
的MagicMock
属性时遇到了麻烦,但是似乎只有在我修补函数时才能使用。但是,我想修补属性。这是一个最小的代码示例:
# in calendar.py
class Weeks():
a = property(lambda self: 0)
b = property(lambda self: 0)
c = property(lambda self: 0)
@patch('calendar.Weeks')
def test_something_else(weeks_mock):
weeks_mock.return_value.a.side_effect = [0, 10, 20, 30]
weeks_mock.return_value.b = 40
weeks_mock.return_value.c = 50
# some more code...
我也没有像这样尝试使用PropertyMock
:
@patch('calendar.Weeks')
def test_something_else(weeks_mock):
type(weeks_mock).a = PropertyMock(side_effect=[0, 10, 20, 30])
weeks_mock.return_value.b = 40
weeks_mock.return_value.c = 50
# some more code...
我将不胜感激!
答案 0 :(得分:1)
使用
__get__
模拟和测试类属性
获取 说明
被调用以获取所有者类的属性(类属性访问)或该类的实例的属性(实例属性访问)。
with mock.patch.object(Weeks, 'a') as mock_a:
mock_a.__get__ = mock.Mock(return_value='mocked_cls_attr')
self.assertEqual(Weeks.a, 'mocked_cls_attr')
不确定为什么会出错,这是一个有效的测试,可帮助您找出错误。
import unittest
import mock
class Weeks():
a = property(lambda self: 0)
b = property(lambda self: 0)
c = property(lambda self: 0)
class TestWeeks(unittest.TestCase):
@mock.patch.object(Weeks, 'a')
@mock.patch.object(Weeks, 'b')
@mock.patch.object(Weeks, 'c')
def test_something_else(self, mockc, mockb, mocka):
# the attr a now mocka is becoming a function using side_effect
mocka.side_effect = [0, 10, 20, 30]
mockb.__get__ = mock.Mock(return_value=40)
mockc.__get__ = mock.Mock(return_value=50)
# mocka() not mocka as it is a function now
self.assertEqual(mocka(), 0)
self.assertEqual(mocka(), 10)
week = Weeks()
self.assertEqual(week.b, 40)
self.assertEqual(week.c, 50)
# week.a with using function will trigger a failure
# AssertionError: <MagicMock name='a' id='139943677051600'> != 20
self.assertEqual(week.a(), 20)
def test_property(self):
# no need to mock a property object, just replace it
week = Weeks()
week.a = property(lambda self: 1)
self.assertTrue(isinstance(week.a, property))
self.assertEqual(week.a.fget(0), 1)
运行测试:
nosetests -v python2_unittests/tests/test_cls_attr.py
结果:
test_something_else (python2_unittests.tests.test_cls_attr.TestWeeks) ... ok
答案 1 :(得分:0)
new_callable
传递给patch
,则 PropertyMock
将起作用:
class Weeks():
a = property(lambda self: 0)
b = property(lambda self: 0)
c = property(lambda self: 0)
@patch('__main__.Weeks.a', new_callable=PropertyMock)
@patch('__main__.Weeks.b', new_callable=PropertyMock)
@patch('__main__.Weeks.c', new_callable=PropertyMock)
def test_something_else(mock_c, mock_b, mock_a):
mock_a.side_effect = [0, 10, 20, 30]
mock_b.return_value = 40
mock_c.return_value = 50
# some more code...
weeks = Weeks()
assert weeks.a == 0
assert weeks.a == 10
assert weeks.b == 40
assert weeks.c == 50
实际上,您使用PropertyMock
的示例适用于a
。我只需要修改b
和c
使其完全起作用:
@patch('__main__.Weeks')
def test_something_else(weeks_mock):
type(weeks_mock).a = PropertyMock(side_effect=[0, 10, 20, 30])
type(weeks_mock).b = PropertyMock(return_value=40)
type(weeks_mock).c = PropertyMock(return_value=50)
# some more code...
assert weeks_mock.a == 0
assert weeks_mock.a == 10
assert weeks_mock.b == 40
assert weeks_mock.c == 50
如果您需要更复杂的逻辑,请直接修补到新的property
:
@patch('__main__.Weeks.a', property(lambda self: 40 if self.b else 50))
def test_something_complicated():
# some more code...
weeks = Weeks()
assert weeks.a == 50