首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >python mock - 在不妨碍实现的情况下修补方法

python mock - 在不妨碍实现的情况下修补方法
EN

Stack Overflow用户
提问于 2018-12-19 00:15:40
回答 2查看 0关注 0票数 0

是否有一种简洁的方法来修补对象,以便您assert_call*在测试用例中获得帮助程序,而无需实际删除操作?

例如,如何修改该@patch行以获得以下测试传递:

代码语言:javascript
复制
from unittest import TestCase
from mock import patch


class Potato(object):
    def foo(self, n):
        return self.bar(n)

    def bar(self, n):
        return n + 2


class PotatoTest(TestCase):

    @patch.object(Potato, 'foo')
    def test_something(self, mock):
        spud = Potato()
        forty_two = spud.foo(n=40)
        mock.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)

我可能会一起使用side_effect,但是我希望有一种更好的方法可以在所有函数,类方法,静态方法,未绑定方法等上以相同的方式工作。

EN

回答 2

Stack Overflow用户

发布于 2018-12-19 08:33:02

与您的类似解决方案,使用wraps

代码语言:javascript
复制
def test_something(self):
    spud = Potato()
    with patch.object(Potato, 'foo', wraps=spud.foo) as mock:
        forty_two = spud.foo(n=40)
        mock.assert_called_once_with(n=40)
    self.assertEqual(forty_two, 42)

根据文件

wrap:要包装的模拟对象的项。如果wrap不是None,那么调用Mock会将调用传递给包装对象(返回实际结果)。模拟器上的属性访问将返回一个Mock对象,该对象包装了包装对象的相应属性(因此,尝试访问不存在的属性将引发AttributeError)。

代码语言:javascript
复制
class Potato(object):

    def spam(self, n):
        return self.foo(n=n)

    def foo(self, n):
        return self.bar(n)

    def bar(self, n):
        return n + 2


class PotatoTest(TestCase):

    def test_something(self):
        spud = Potato()
        with patch.object(Potato, 'foo', wraps=spud.foo) as mock:
            forty_two = spud.spam(n=40)
            mock.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)
票数 0
EN

Stack Overflow用户

发布于 2018-12-19 09:34:00

这个答案解决了用户Quuxplusone的赏金中提到的额外要求:

对我的用例来说重要的是它可以使用@patch.mock,即它不需要我在构造Potatospud在这个例子中)的实例和我的调用之间插入任何代码spud.foo。我需要从一开始就使用模拟方法spud创建foo,因为我无法控制spud创建的位置。

使用decorator可以毫不费力地实现上述用例:

代码语言:javascript
复制
import unittest
import unittest.mock  # Python 3

def spy_decorator(method_to_decorate):
    mock = unittest.mock.MagicMock()
    def wrapper(self, *args, **kwargs):
        mock(*args, **kwargs)
        return method_to_decorate(self, *args, **kwargs)
    wrapper.mock = mock
    return wrapper

def spam(n=42):
    spud = Potato()
    return spud.foo(n=n)

class Potato(object):

    def foo(self, n):
        return self.bar(n)

    def bar(self, n):
        return n + 2

class PotatoTest(unittest.TestCase):

    def test_something(self):
        foo = spy_decorator(Potato.foo)
        with unittest.mock.patch.object(Potato, 'foo', foo):
            forty_two = spam(n=40)
        foo.mock.assert_called_once_with(n=40)
        self.assertEqual(forty_two, 42)


if __name__ == '__main__':
    unittest.main()

如果替换的方法接受在测试下修改的可变参数,则可能希望初始化CopyingMock代替MagicMock在spy_decorator内部。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100006318

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档