【问题标题】:How to check if a function was called in a unit test using pytest-mock?如何使用 pytest-mock 检查是否在单元测试中调用了函数?
【发布时间】:2018-04-13 00:01:19
【问题描述】:

我有一个单元测试,我想检查一个函数是否被调用。我如何使用pytestpytest-mock 库来做到这一点?

例如,这是一个单元测试test_hello.py。在这个测试中,我调用函数 my_function 并想验证它是否使用给定的参数调用了 hello

def hello(name):
    return f'Hello {name}'

def my_function():
    hello('Sam')

def test_hello(mocker):
    mocker.patch('hello')
    my_function()
    hello.assert_called_once_with('Sam')

上面的代码返回如下错误:

target = 'hello'

    def _get_target(target):
        try:
>           target, attribute = target.rsplit('.', 1)
E           ValueError: not enough values to unpack (expected 2, got 1)

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py:1393: ValueError

During handling of the above exception, another exception occurred:

mocker = <pytest_mock.MockFixture object at 0x109c5e978>

    def test_hello(mocker):
>       mocker.patch('hello')

test_hello.py:8: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pytest_mock.py:156: in __call__
    return self._start_patch(self.mock_module.patch, *args, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pytest_mock.py:134: in _start_patch
    p = mock_func(*args, **kwargs)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py:1544: in patch
    getter, attribute = _get_target(target)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

target = 'hello'

    def _get_target(target):
        try:
            target, attribute = target.rsplit('.', 1)
        except (TypeError, ValueError):
            raise TypeError("Need a valid target to patch. You supplied: %r" %
>                           (target,))
E           TypeError: Need a valid target to patch. You supplied: 'hello'

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/mock.py:1396: TypeError

【问题讨论】:

标签: python unit-testing mocking pytest


【解决方案1】:

解决错误

mocked_hello 分配给mocked.patch

side_effect 分配给模拟函数

def bonjour(name):
    return 'bonjour {}'.format(name)


def hello(name):
    return 'Hello {}'.format(name)


def my_function():
   return hello('Sam')


def test_hellow_differnt_from_module(mocker):
    # mocked func with `test_hello.py` as module name
    mocked_hello = mocker.patch('test_hello.hello')
    # assign side_effect to mocked func
    mocked_hello.side_effect = bonjour
    # the mocked func return_value changed by side_effect
    assert mocked_hello('Sam') == 'bonjour Sam'
    # the mocked func called with Sam, but with different return value
    mocked_hello.assert_called_with('Sam')

调用一个真正的函数 my_function() 并验证它是否调用了 hello

def test_my_function(mocker):
    mocker.patch('test_hello.hello', side_effect=bonjour)
    mf = my_function()
    hello.assert_called_with('Sam')
    assert mf == 'bonjour Sam'

【讨论】:

  • 感谢您的帮助,当我运行您的代码 pytest test_hello.py 时,它给了我错误:“ModuleNotFoundError: No module named 'test_hello'”。
  • @Evgenii,你有test_hello.pytest_hello() 函数,这可能会搞砸import,我跑了python -m pytest test_hello.py
  • 感谢@Gang 的帮助,但这不是我想做的。在test_hellow_differnt_from_module() 中,您正在调用模拟函数mocked_hello()。但是,我想调用一个真正的函数my_function() 并验证它是否调用了hello()
  • 这些都没有出现在 pytest 文档中。如何使用 pytest?
【解决方案2】:

我认为对 OP 的代码进行最小的更改以使其正常工作只是完全限定模拟函数的名称。因此,例如,如果代码位于名为 test.py 的文件中:

import pytest

def hello(name):
    return f'Hello {name}'

def my_function():
    hello('Sam')

def test_hello(mocker):
    mocker.patch('test.hello')
    my_function()
    hello.assert_called_once_with('Sam')

(我假设test.py 位于sys.path 的某个地方。)

但是,我认为最好将测试功能更改为:

def test_hello(mocker):
    mocked_func = mocker.patch('test.hello')
    my_function()
    mocked_func.assert_called_once_with('Sam')

这种形式对我来说似乎更清晰,并且不太可能在更复杂的代码中引发 AttributeError。

【讨论】:

    猜你喜欢
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多