【问题标题】:Python unit test mock, get mocked function's input argumentsPython单元测试模拟,获取模拟函数的输入参数
【发布时间】:2015-09-16 17:21:33
【问题描述】:

我想要一个单元测试来断言函数中的变量action 被设置为它的预期值,这个变量唯一被使用的时候是当它被传递到一个库的调用中时。

Class Monolith(object):
    def foo(self, raw_event):
        action =  # ... Parse Event
        # Middle of function
        lib.event.Event(METADATA, action)
        # Continue on to use the build event.

我的想法是我可以模拟lib.event.Event,并获取它的输入参数并断言它们具有特定的价值。

>这不是模拟的工作方式吗?模拟文档的不一致、半示例以及与我想做的事情无关的过多示例让我感到沮丧。

【问题讨论】:

  • 你在哪里使用过模拟?你可以模拟lib.event.Event 并断言
  • 回想起来,这种补丁和模拟方法现在看起来比当时更自然/事实上

标签: python unit-testing mocking


【解决方案1】:

您也可以使用call_args 或call_args_list。

一个简单的例子如下所示:

import mock
import unittest

class TestExample(unittest.TestCase):

    @mock.patch('lib.event.Event')
    def test_example1(self, event_mocked):
        args, kwargs = event_mocked.call_args
        args = event_mocked.call_args.args  # alternatively 
        self.assertEqual(args, ['metadata_example', 'action_example'])

我只是为可能需要它的人快速编写了这个示例 - 我没有实际测试过这个,所以可能存在一些小错误。

【讨论】:

  • 对我来说,我必须这样做self.assertEqual(event_mocked.call_args[0], <expected_args>)。 event_mocked.call_args.args 对我不起作用。可能是版本问题?
  • @Josmoor98 如果是版本问题,如果您可以分享您的 Python 版本,可能会对某人有所帮助。
  • 确实,正如 cmets 中指出的,python 版本 - Python 3.6.12 - [PyPy 7.3.3 with GCC 9.3.0]
【解决方案2】:

您可以使用补丁装饰器,然后像这样调用 assert_called_with 来模拟对象:

如果你有这个结构:

example.py
tests.py
lib/__init__.py
lib/event.py

而example.py的内容是:

import lib

METADATA = 'metadata_example'

class Monolith(object):

    def foo(self, raw_event):
        action =  'action_example' # ... Parse Event
        # Middle of function
        lib.event.Event(METADATA, action)
        # Continue on to use the build event.

而lib/event.py的内容是:

class Event(object):

    def __init__(self, metadata, action):
        pass

tests.py 的代码应该是这样的:

import mock
import unittest

from lib.event import Event
from example import Monolith


class TestExample(unittest.TestCase):

    @mock.patch('lib.event.Event')
    def test_example1(self, event_mocked):
        # Setup
        m = Monolith()

        # Exercise
        m.foo('raw_event')

        # Verify
        event_mocked.assert_called_with('metadata_example', 'action_example')

【讨论】:

  • 如果我想将参数作为字典传递给 mock 怎么办?
  • @dopatraman 您可以使用call_args 或call_args_list。
  • @CraigAnderson 你能把它作为答案发布吗?
  • @StevenVascellaro 这并不是原始问题的真正答案,是吗?我已提议对此答案进行修改,以说明如何使用它们。
【解决方案3】:

如果你想直接访问参数,这个怎么样?虽然有点多余... 见https://docs.python.org/3.6/library/unittest.mock.html#unittest.mock.call.call_list

import mock
import unittest

from lib.event import Event
from example import Monolith


class TestExample(unittest.TestCase):

    @mock.patch('lib.event.Event')
    def test_example1(self, event_mocked):
        # Setup
        m = Monolith()

        # Exercise
        m.foo('raw_event')

        # Verify
        name, args, kwargs = m.mock_calls[0]
        self.assertEquals(name, "foo")
        self.assertEquals(args, ['metadata_example', 'action_example'])
        self.assertEquals(kwargs, {})

【讨论】:

    猜你喜欢
    • 2019-04-09
    • 2013-04-16
    • 2021-09-10
    • 2023-04-03
    • 1970-01-01
    • 2015-11-13
    • 2017-03-24
    • 2010-11-17
    • 1970-01-01
    相关资源
    最近更新 更多