Python模拟中的模拟属性?

Posted

技术标签:

【中文标题】Python模拟中的模拟属性?【英文标题】:Mock attributes in Python mock? 【发布时间】:2013-05-27 21:05:04 【问题描述】:

我在 Python 中使用 mock 时遇到了相当困难:

def method_under_test():
    r = requests.post("http://localhost/post")

    print r.ok # prints "<MagicMock name='post().ok' id='11111111'>"

    if r.ok:
       return StartResult()
    else:
       raise Exception()

class MethodUnderTestTest(TestCase):

    def test_method_under_test(self):
        with patch('requests.post') as patched_post:
            patched_post.return_value.ok = True

            result = method_under_test()

            self.assertEqual(type(result), StartResult,
                "Failed to return a StartResult.")

测试实际上返回了正确的值,但r.ok 是一个Mock 对象,而不是True。如何模拟 Python 的 mock 库中的属性?

【问题讨论】:

【参考方案1】:

你需要使用return_valuePropertyMock

with patch('requests.post') as patched_post:
    type(patched_post.return_value).ok = PropertyMock(return_value=True)

这意味着:当调用requests.post 时,在该调用的返回值上,为属性ok 设置一个PropertyMock 以返回值True

【讨论】:

如果我从method_under_test 中得到print r.ok 的值,我看到的是&lt;MagicMock name='post().ok' id='57360464'&gt;,而不是True @TKKocheran:我已经更新了我的答案。您还需要使用PropertyMock 为什么不简单地使用patched_post.return_value = mock.Mock(ok=True) @lumbric 因为您可以使用PropertyMock 断言它已像任何其他Mock 对象一样被访问。仅仅为属性赋值是无法做到的。【参考方案2】:

一个紧凑而简单的方法是使用new_callablepatch的属性来强制patch使用PropertyMock而不是MagicMock来创建模拟对象。传递给patch 的其他参数将用于创建PropertyMock 对象。

with patch('requests.post.ok', new_callable=PropertyMock, return_value=True) as mock_post:
    """Your test"""

【讨论】:

【参考方案3】:

使用模拟版本“1.0.1”,支持问题中提到的更简单的语法并按原样工作!

更新示例代码(使用py.test代替unittest):

import mock
import requests


def method_under_test():
    r = requests.post("http://localhost/post")

    print r.ok

    if r.ok:
        return r.ok
    else:
        raise Exception()


def test_method_under_test():
    with mock.patch('requests.post') as patched_post:
        patched_post.return_value.ok = True

        result = method_under_test()
        assert result is True, "mock ok failed"

使用以下代码运行此代码:(确保安装 pytest)

$ py.test -s -v mock_attributes.py 
======= test session starts =======================
platform linux2 -- Python 2.7.10 -- py-1.4.30 -- pytest-2.7.2 -- /home/developer/miniconda/bin/python
rootdir: /home/developer/projects/learn/scripts/misc, inifile: 
plugins: httpbin, cov
collected 1 items 

mock_attributes.py::test_method_under_test True
PASSED

======= 1 passed in 0.03 seconds =================

【讨论】:

这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 仅供参考 requests.post.ok 是一个属性,而不是一个属性。如果您尝试使用ok 是简单属性的简单对象,则问题中提到的语法有效,但对于requests.post.ok 对象编号:它将引发AttributeError @philant 感谢您的反馈,正如示例所证明的,这是对该问题的最新答案,而且语法恰好更简单。 @Micheled'Amico 感谢您的反馈,我试过了,请看一下 ;-)

以上是关于Python模拟中的模拟属性?的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象编程

部分模拟一个类而不影响 PHP 中的私有属性

如何使用powermockito,模拟一个类中的私有静态属性,而且这个属性是了工

Angular2(TypeScript)中的单元测试/模拟窗口属性

使用Python中的字典模拟类

Python中的几何布朗运动模拟