Python:在测试函数的同一模块中定义的修补函数

Nic*_*mek 6 python unit-testing patch mocking python-unittest.mock

我一直在使用Python的unittest.mock库,但是现在我正在努力解决可能无法正确处理的用例.

考虑一个mymodule/code.py包含以下代码段的文件:

def sum():
  pass

def mul():
  pass

def div():
  pass

def get_functions():
  return [sum, mul, div]

def foo():
  functions = get_functions()
  for func in functions:
    func()
Run Code Online (Sandbox Code Playgroud)

我想测试的foo功能,修补sum功能,并留下muldiv,因为它们.这是我最初尝试过的:

class TestFoo(unittest.TestCase):
  @mock.patch('mymodule.code.foo.sum')
  def test_foo(foo_sum_mock):
    foo()
    foo_sum_mock.assert_called_once()
Run Code Online (Sandbox Code Playgroud)

但是,上面说明的修补方法不起作用.我相信sum在加载时该函数已正确修补mymodule.code.py,但由于def sum()块而重新定义.

通过阅读官方文档,我还尝试使用库的startstop函数unittest.mock如下:

def test_foo():
  patcher = mock.patch('module.code.sum')
  mocked_sum_fun = patcher.start()

  foo()

  mocked_sum_fun.assert_called_once()
  mock_sum_fun.stop()
Run Code Online (Sandbox Code Playgroud)

这种方法也行不通.我希望它会summodules/code.py文件加载后避免函数覆盖.

是否可以修补本地功能,如sum?或者将sum功能移动到另一个文件是修补的唯一选择?

提前谢谢了!

Mau*_*ldi 5

您可以使用该模块来模拟同一模块的函数mock.patch并将其引用为__main__

代码.py

from unittest.mock import patch

def sum():
    print("called method sum")
    pass

def call_sum():
    sum()

def return_mock():
    print("I'm a mocked method")
    return True

with patch('__main__.sum', return_value=return_mock()) as mock_test:
    call_sum()
    mock_test.assert_called_once() # assure that mocked method was called, not original.

Run Code Online (Sandbox Code Playgroud)

您还可以使用 lib() 的路径my_project.code.sum代替__main__.sum.

  • 收到 ModuleNotFoundError,`'__main__' 不是一个包`。 (2认同)
  • 这在很大程度上取决于它的名称。我在某个地方发现可靠的方法是使用“__name__ + '.sum'”之类的东西。 (2认同)

小智 -3

一般来说,您希望将测试代码与生产代码分开:

代码.py

def sum():
    pass

def mul():
    pass

def div():
    pass

def get_functions():
    return [sum, mul, div]

def foo():
    functions = get_functions()
    for func in functions:
        func()
Run Code Online (Sandbox Code Playgroud)

代码测试.py

import unittest
import mock_test as mock
import code

class TestFoo(unittest.TestCase):
    @mock.patch('code.sum')
    def test_foo(self, sum_mock):
        def new_sum_mock(*args, **kwargs):
            # mock code here
            pass
        sum_mock.side_effect = new_sum_mock
        code.foo()
        sum_mock.assert_called_once()
Run Code Online (Sandbox Code Playgroud)

但是,是的,您可以将它们全部放入一个文件中:

代码_测试.py:

import unittest
import mock_test as mock
import code

def sum():
    pass


def mul():
    pass


def div():
    pass


def get_functions():
    return [sum, mul, div]


def foo():
    functions = get_functions()
    for func in functions:
        func()


class TestFoo(unittest.TestCase):

    @mock.patch('code_test.sum')
    def test_foo(self, sum_mock):
        def new_sum_mock(*args, **kwargs):
            # mock code here
            pass

        sum_mock.side_effect = new_sum_mock
        code.foo()
        sum_mock.assert_called_once()
Run Code Online (Sandbox Code Playgroud)