Python:如何在单元测试期间覆盖复杂的函数?

Rob*_*ert 6 python mocking python-unittest

我正在使用 Python 的unittest模块来测试我正在编写的脚本。

该脚本包含一个如下循环:

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c
Run Code Online (Sandbox Code Playgroud)

unittest我使用测试没有任何问题complicated_function。但我想my_loopy_function通过覆盖来测试complicated_function

我尝试修改我的脚本,以便my_loopy_functioncomplicated_function其作为可选参数,以便我可以从测试中传递一个简单的版本:

// my_modified_script.py

def my_loopy_function(action_function=None):
    if action_function is not None:
        complicated_function = action_function
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c

// test_my_script.py

from myscript import my_loopy_function

class TestMyScript(unittest.TestCase):
    test_loopy_function(self):
        def simple_function():
            return 1
    self.assertEqual(10, my_loopy_function(action_function=simple_function))
Run Code Online (Sandbox Code Playgroud)

它没有像我希望的那样工作,对于我应该如何做到这一点有什么建议吗?

Rob*_*ert 8

最后我使用了Python mock,它允许我重写complicated_function而无需以任何方式调整原始代码。

这是原始脚本,请注意,它没有作为“ ”参数complicated_function传递(这是我在之前的解决方案中尝试过的):my_loopy_functionaction_function

// my_script.py

def my_loopy_function():
    aggregate_value = 0
    for x in range(10):
        aggregate_value = aggregate_value + complicated_function(x)
    return aggregate_value

def complicated_function(x):
    a = do()
    b = something()
    c = complicated()
    return a + b + c
Run Code Online (Sandbox Code Playgroud)

这是我用来测试它的脚本:

// test_my_script.py

import unittest
import mock
from my_script import my_loopy_function

class TestMyModule(unittest.TestCase):
    @mock.patch('my_script.complicated_function')
    def test_1(self, mocked):
        mocked.return_value = 1
        self.assertEqual(10, my_loopy_function())
Run Code Online (Sandbox Code Playgroud)

这正如我所希望的那样工作:

  1. 我可以用更简单的版本来替换函数,这样我可以更轻松地测试,
  2. 我不需要以任何方式改变我的原始代码(就像我正在尝试的那样——这是通过传递函数指针来有效地实现的),该mock模块使我可以对内部结构进行后编码访问。

感谢奥斯汀提出使用mock. 顺便说一句,我使用的是 Python 2.7,因此使用了PyPI 中的pip-installable mock