【问题标题】:Python mock library: Is there any way to get corresponding return values from magic mock calls?Python 模拟库:有没有办法从魔术模拟调用中获取相应的返回值?
【发布时间】:2013-08-02 23:31:22
【问题描述】:

在使用mock 库编写 Python 测试时,我经常会得到这样的“调用方法的参数”,

from __future__ import print_function
import mock

m = mock.MagicMock(side_effect=lambda x: x * x)
m(4)
print("m called with: ", m.call_args_list)

(这将打印m called with: [call(4)])。 问题:有什么方法可以获取返回值(本例为16)?

详细信息:在我的特定场景中,我想使用 side_effect 返回一个子模拟对象:内省该对象以查看对其调用的内容很重要。例如,“真实代码”(非测试代码)可能会写,

myobj = m(4)
myobj.foo()

使用side_effect 似乎是一种返回新子模拟对象的便捷方式,但也可以保留call_args_list。但是,MagicMock 似乎没有存储来自side_effect 函数的返回值……我错了吗?

【问题讨论】:

    标签: python unit-testing mocking python-mock


    【解决方案1】:

    如果你问我,这不是模拟的目的。如果要断言返回值,则应直接调用该函数。如果您需要跳过箍来注册函数返回的内容,那么您的设计很可能存在缺陷。

    例如,如果您有一个内部函数,则不应测试该内部函数。如果您想测试内部函数,请将其公开访问。

    所以不要这样:

    def spam(input):
        def eggs(nested):
            return nested*2
        input = eggs(nested)
        return eggs(input)
    

    这样做:

    def eggs(nested):
        return nested*2
    
    def spam(input):
        input = eggs(nested)
        return eggs(input)
    

    【讨论】:

      【解决方案2】:

      wraps 参数呢?

      class MyClass:
          def foo(self, x):
              return(x * x)
      

      然后你可以断言这样的调用:

      my_obj = MyClass()
      with patch.object(MyClass, 'foo', wraps=MyClass().foo) as mocked_foo:
          my_result = my_obj.foo(4)
          mocked_foo.assert_called_with(4)    
      

      而 my_result 将包含调用 foo() 的实际结果

      【讨论】:

        【解决方案3】:

        你不需要side_effect,这就是没有它的模拟已经做了,他们返回其他模拟。

        你可以通过mymock.return_value.assert_called_once_with(4)对它们进行断言

        如果你这样做了,你只需要返回一个你在 side_effect 其他地方引用过的模拟。

        【讨论】:

        • 我希望“返回的其他模拟”变得特别。 m(4) 不仅仅是另一个 MagicMock,而是一个具有某种状态的对象(在我的例子中,模拟了一个 Redis 服务器)。不过谢谢!
        • 然后用m.return_value进行配置。
        【解决方案4】:

        使用return_value

        例如,

        import unittest
        
        import mock
        
        def foo(m):
            myobj = m(4)
            myobj.foo()
        
        import unittest
        
        class TestFoo(unittest.TestCase):
            def test_foo(self):
                m2 = mock.MagicMock()
                m = mock.MagicMock(return_value=m2)
        
                foo(m)
        
                m.assert_called_once_with(4)
                m2.foo.assert_called_once_with()
        
        if __name__ == '__main__':
            unittest.main()
        

        【讨论】:

        • 这需要修改非测试代码,即调用m(4)。
        【解决方案5】:

        你有一个 call() 对象。 您想在调用对象中获取参数。 也就是说,如果你得到 ​​p>

        call_args_list[0] == call(3, 5)
        

        你想要 3 和 5。 call() 对象可以被索引 - 首先参考 elem 0,它是实际参数的列表。然后,你想要 3,它在里面作为第 0 个元素。

        通过以下方式获取:

        cargs = call_args_list[0]
        assert cargs[0][0] == 3
        
        >>> mockObjThing.someFunc.call_args_list[0]
        call('argOne', 'argTwo') 
        >>> # DAGNABBIT I want argOne!!!
        >>> cargs = mockObjThing.someFunc.call_args_list[0]
        >>> cargs
        call('argOne', 'argTwo') 
        >>> cargs[0]
        ('argOne', 'argTwo')
        >>> cargs[0][0]
        'argOne'
        

        【讨论】:

          猜你喜欢
          • 2010-09-09
          • 1970-01-01
          • 2014-10-07
          • 1970-01-01
          • 2023-03-24
          • 2013-09-30
          • 2022-10-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多