python - 模拟类方法并更改 Python 中的一些对象属性

标签 python unit-testing testing mocking patch

我是 Python 模拟新手。我想知道如何在用另一个类方法进行测试时替换(模拟)一个类方法,知道原始方法只是更改了 self 的某些属性而不返回任何值。例如:

def some_method(self):   
    self.x = 4   
    self.y = 6   

所以在这里我不能只更改模拟的 return_value。我试图定义一个新函数(应该替换原来的函数)并将其作为 side_effect 提供给模拟。但是我怎样才能让模拟函数改变类中对象的属性。 这是我的代码:

@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 参数的呢?是测试类的self,还是被测类的对象self?

最佳答案

如果我不明白您要做什么,请提前致歉,但我认为这可能有效:

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

编辑:回答有关如何在不模拟类的情况下在测试函数内部执行的问题...

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() ,否则您可能会遇到补丁处于事件状态但您不希望它处于事件状态的情况。请注意,要在测试代码函数中定义 mock 函数,我没有使用 patch 作为装饰器,因为必须在 patch 中使用“new”关键字之前定义 mock 函数。如果你想使用 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()

这些都没有使用副作用,但它们都解决了模拟类方法和更改某些属性的问题。您选择哪一个取决于应用程序。

关于python - 模拟类方法并更改 Python 中的一些对象属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34406848/

相关文章:

python - SQLAlchemy 和 django,准备好生产了吗?

unit-testing - 我们如何使用angulardart中的测试包对异步函数进行单元测试?

javascript - 单元测试依赖于其他 getter 的 Vuex getter

java - 如何在测试中加载 spring HTTPInvoker 到 jetty?

windows - 在软件中测试网络中断

python - 在 Python 中,如何将整数和字符串列表转换为 Unicode?

python - Django 中的 MySQLdb 错误

python - 为什么我在位置 0 : invalid continuation byte "problem and how do I solve it? 处有 "' utf- 8' codec can' t 解码字节 0xc4

reactjs - 如何为调用 props 中接收的函数的函数添加单元测试

python - 如何仅在测试类而不是单元测试用例中模拟函数