模拟 class 方法并更改 Python 中的一些对象属性
Mocking a class method and changing some object attributes in Python
我是 Python 中的新手。我想知道如何在使用另一个方法进行测试时替换(模拟)class 方法,知道原始方法只是更改了 self 的某些属性而不返回任何值。例如:
def some_method(self):
self.x = 4
self.y = 6
所以在这里我不能只更改模拟的 return_value。我试图定义一个新函数(应该替换原来的函数)并将其作为 side_effect 提供给模拟。但是我怎样才能让模拟函数改变class中对象的属性。
这是我的代码:
@patch('path.myClass.some_method')
def test_this(self,someMethod):
def replacer(self):
self.x = 5
self.y = 16
some_method.side_effect = replacer
那么 Python 现在如何理解 replacer 的 self
参数?是被测class的自己,还是被测class的对象自己?
如果我不明白您要做什么,请提前致歉,但我认为这可能有效:
import unittest
from unittest.mock import patch
class MyClass:
def __init__(self):
self.x = 0
self.y = 0
def some_method(self):
self.x = 4
self.y = 6
class OtherClass:
def other_method(self):
self.x = 5
self.y = 16
class MyTestClass(unittest.TestCase):
@patch('__main__.MyClass.some_method', new=OtherClass.other_method)
def test_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
def test_not_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 4)
self.assertEqual(a.y, 6)
if __name__ == "__main__":
unittest.main()
打补丁时用other_method()替换some_method(),为属性x,y设置不同的值,当测试为运行时,给出结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.020s
OK
编辑:回答有关如何在不模拟 class...
的情况下在测试函数内部执行的问题
def test_inside_patch(self):
def othermethod(self):
self.x = 5
self.y = 16
patcher = patch('__main__.MyClass.some_method', new=othermethod)
patcher.start()
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
patcher.stop()
确保您在补丁程序上调用了 start() 和 stop() ,否则您可能会遇到补丁处于活动状态但您不希望它处于活动状态的情况。请注意,要在测试代码函数中定义模拟函数,我没有使用 patch 作为装饰器,因为必须在 patch 中使用 'new' 关键字之前定义模拟函数。如果你想使用 patch 作为装饰器,你必须在 patch 之前的某个地方定义 mock 函数,在 MyTestClass 中定义它也可以,但看起来你真的想在你的测试函数代码中定义 mock 函数。
编辑:添加了我看到的 4 种方法的摘要...
# first way uses a class outside MyTest class
class OtherClass:
def other_method(self):
...
class MyTest(unittest.TestCase):
@patch('path_to_MyClass.some_method', new=OtherClass.other_method)
def test_1(self)
...
# 2nd way uses class defined inside test class
class MyOtherClass:
def other_method(self):
...
@patch('path_to_MyClass.some_method', new=MyOtherClass.other_method)
def test_2(self):
...
# 3rd way uses function defined inside test class but before patch decorator
def another_method(self):
...
@patch('path_to_MyClass.some_method', new=another_method)
def test_3(self):
...
# 4th way uses function defined inside test function but without a decorator
def test_4(self):
def yet_another_method(self):
...
patcher = patch('path_to_MyClass.some_method', new=yet_another_method)
patcher.start()
...
patcher.stop()
其中 None 使用了 side_effect,但它们都解决了模拟 class 方法和更改某些属性的问题。选择哪一个取决于应用程序。
我是 Python 中的新手。我想知道如何在使用另一个方法进行测试时替换(模拟)class 方法,知道原始方法只是更改了 self 的某些属性而不返回任何值。例如:
def some_method(self):
self.x = 4
self.y = 6
所以在这里我不能只更改模拟的 return_value。我试图定义一个新函数(应该替换原来的函数)并将其作为 side_effect 提供给模拟。但是我怎样才能让模拟函数改变class中对象的属性。 这是我的代码:
@patch('path.myClass.some_method')
def test_this(self,someMethod):
def replacer(self):
self.x = 5
self.y = 16
some_method.side_effect = replacer
那么 Python 现在如何理解 replacer 的 self
参数?是被测class的自己,还是被测class的对象自己?
如果我不明白您要做什么,请提前致歉,但我认为这可能有效:
import unittest
from unittest.mock import patch
class MyClass:
def __init__(self):
self.x = 0
self.y = 0
def some_method(self):
self.x = 4
self.y = 6
class OtherClass:
def other_method(self):
self.x = 5
self.y = 16
class MyTestClass(unittest.TestCase):
@patch('__main__.MyClass.some_method', new=OtherClass.other_method)
def test_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
def test_not_patched(self):
a = MyClass()
a.some_method()
self.assertEqual(a.x, 4)
self.assertEqual(a.y, 6)
if __name__ == "__main__":
unittest.main()
打补丁时用other_method()替换some_method(),为属性x,y设置不同的值,当测试为运行时,给出结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.020s
OK
编辑:回答有关如何在不模拟 class...
的情况下在测试函数内部执行的问题def test_inside_patch(self):
def othermethod(self):
self.x = 5
self.y = 16
patcher = patch('__main__.MyClass.some_method', new=othermethod)
patcher.start()
a = MyClass()
a.some_method()
self.assertEqual(a.x, 5)
self.assertEqual(a.y, 16)
patcher.stop()
确保您在补丁程序上调用了 start() 和 stop() ,否则您可能会遇到补丁处于活动状态但您不希望它处于活动状态的情况。请注意,要在测试代码函数中定义模拟函数,我没有使用 patch 作为装饰器,因为必须在 patch 中使用 'new' 关键字之前定义模拟函数。如果你想使用 patch 作为装饰器,你必须在 patch 之前的某个地方定义 mock 函数,在 MyTestClass 中定义它也可以,但看起来你真的想在你的测试函数代码中定义 mock 函数。
编辑:添加了我看到的 4 种方法的摘要...
# first way uses a class outside MyTest class
class OtherClass:
def other_method(self):
...
class MyTest(unittest.TestCase):
@patch('path_to_MyClass.some_method', new=OtherClass.other_method)
def test_1(self)
...
# 2nd way uses class defined inside test class
class MyOtherClass:
def other_method(self):
...
@patch('path_to_MyClass.some_method', new=MyOtherClass.other_method)
def test_2(self):
...
# 3rd way uses function defined inside test class but before patch decorator
def another_method(self):
...
@patch('path_to_MyClass.some_method', new=another_method)
def test_3(self):
...
# 4th way uses function defined inside test function but without a decorator
def test_4(self):
def yet_another_method(self):
...
patcher = patch('path_to_MyClass.some_method', new=yet_another_method)
patcher.start()
...
patcher.stop()
其中 None 使用了 side_effect,但它们都解决了模拟 class 方法和更改某些属性的问题。选择哪一个取决于应用程序。