模拟 Python class 的方法和属性的子集
Mock a subset of a Python class's methods and properties
我正在使用 mock
Python 模块来执行我的测试。
有时我会模拟 class,但我只想模拟它的一些方法和属性,而不是全部。
假设以下场景:
# module.py
class SomeClass:
def some_method(self):
return 100
def another_method(self):
return 500
# test.py
class Tests(unittest.TestCase):
@patch('module.SomeClass')
def test_some_operation(self, some_class_mock):
some_class_instance = some_class_mock.return_value
# I'm mocking only the some_method method.
some_class_instance.some_method.return_value = 25
# This is ok, the specific method I mocked returns the value I wished.
self.assertEquals(
25,
SomeClass().some_method()
)
# However, another_method, which I didn't mock, returns a MagicMock instance
# instead of the original value 500
self.assertEquals(
500,
SomeClass().another_method()
)
在上面的代码中,一旦我修补 SomeClass
class,就会调用 return_values 的方法
我没有明确设置 will return MagicMock
objects.
我的问题是:如何才能仅模拟 class 方法中的一部分,而保持其他方法完好无损?
我能想到的有两种方法,但是none种方法真的很好。
一种方法是将mock的方法设置为原来的class方法,像这样:
some_class_instance.another_method = SomeClass.another_method
这不是真正可取的,因为 class 可能有很多方法和属性
“取消模拟”。
另一种方法是对我明确想要的每个方法进行修补,例如:
@patch('module.SomeClass.some_method')
def test_some_operation(self, some_method_mock):
但是如果我想模拟 class 本身,这并不能真正起作用,因为模拟调用
例如初始化程序。无论如何,下面的代码将覆盖所有 SomeClass
的方法。
@patch('module.SomeClass.some_method')
@patch('module.SomeClass')
def test_some_operation(self, some_class_mock, some_method_mock):
这里有一个更具体的例子:
class Order:
def process_event(self, event, data):
if event == 'event_a':
return self.process_event_a(data)
elif event == 'event_b':
return self.process_event_b(data)
else:
return None
def process_event_a(self, data):
# do something with data
def process_event_b(self, data):
# do something different with data
在这种情况下,我有一个通用方法 process_event
,它根据提供的事件调用特定的处理事件。
我只想测试方法process_event
。我只想知道是否根据我提供的事件调用了正确的特定事件。
因此,在我的测试用例中,我想做的是仅模拟 process_event_a
和 process_event_b
,使用特定参数调用原始 process_event
,然后断言 process_event_a
或 process_event_b
使用正确的参数调用。
您必须修补对象而不是修补整个 class。即,创建您的 class 的实例,然后修补该实例的方法。
请注意,您也可以使用装饰器 @patch.object
而不是我的方法。
class SomeClass:
def some_method(self):
return 100
def another_method(self):
return 500
在你的test.py
from unittest import mock
class Tests(unittest.TestCase):
def test_some_operation(self):
some_class_instance = SomeClass()
# I'm mocking only the some_method method.
with mock.patch.object(some_class_instance, 'some_method', return_value=25) as cm:
# This is gonna be ok
self.assertEquals(
25,
SomeClass().some_method()
)
# The other methods work as they were supposed to.
self.assertEquals(
500,
SomeClass().another_method()
)
我正在使用 mock
Python 模块来执行我的测试。
有时我会模拟 class,但我只想模拟它的一些方法和属性,而不是全部。
假设以下场景:
# module.py
class SomeClass:
def some_method(self):
return 100
def another_method(self):
return 500
# test.py
class Tests(unittest.TestCase):
@patch('module.SomeClass')
def test_some_operation(self, some_class_mock):
some_class_instance = some_class_mock.return_value
# I'm mocking only the some_method method.
some_class_instance.some_method.return_value = 25
# This is ok, the specific method I mocked returns the value I wished.
self.assertEquals(
25,
SomeClass().some_method()
)
# However, another_method, which I didn't mock, returns a MagicMock instance
# instead of the original value 500
self.assertEquals(
500,
SomeClass().another_method()
)
在上面的代码中,一旦我修补 SomeClass
class,就会调用 return_values 的方法
我没有明确设置 will return MagicMock
objects.
我的问题是:如何才能仅模拟 class 方法中的一部分,而保持其他方法完好无损?
我能想到的有两种方法,但是none种方法真的很好。
一种方法是将mock的方法设置为原来的class方法,像这样:
some_class_instance.another_method = SomeClass.another_method
这不是真正可取的,因为 class 可能有很多方法和属性 “取消模拟”。
另一种方法是对我明确想要的每个方法进行修补,例如:
@patch('module.SomeClass.some_method') def test_some_operation(self, some_method_mock):
但是如果我想模拟 class 本身,这并不能真正起作用,因为模拟调用 例如初始化程序。无论如何,下面的代码将覆盖所有
SomeClass
的方法。@patch('module.SomeClass.some_method') @patch('module.SomeClass') def test_some_operation(self, some_class_mock, some_method_mock):
这里有一个更具体的例子:
class Order:
def process_event(self, event, data):
if event == 'event_a':
return self.process_event_a(data)
elif event == 'event_b':
return self.process_event_b(data)
else:
return None
def process_event_a(self, data):
# do something with data
def process_event_b(self, data):
# do something different with data
在这种情况下,我有一个通用方法 process_event
,它根据提供的事件调用特定的处理事件。
我只想测试方法process_event
。我只想知道是否根据我提供的事件调用了正确的特定事件。
因此,在我的测试用例中,我想做的是仅模拟 process_event_a
和 process_event_b
,使用特定参数调用原始 process_event
,然后断言 process_event_a
或 process_event_b
使用正确的参数调用。
您必须修补对象而不是修补整个 class。即,创建您的 class 的实例,然后修补该实例的方法。
请注意,您也可以使用装饰器 @patch.object
而不是我的方法。
class SomeClass:
def some_method(self):
return 100
def another_method(self):
return 500
在你的test.py
from unittest import mock
class Tests(unittest.TestCase):
def test_some_operation(self):
some_class_instance = SomeClass()
# I'm mocking only the some_method method.
with mock.patch.object(some_class_instance, 'some_method', return_value=25) as cm:
# This is gonna be ok
self.assertEquals(
25,
SomeClass().some_method()
)
# The other methods work as they were supposed to.
self.assertEquals(
500,
SomeClass().another_method()
)