python mock patch decorator对类方法和单个函数的行为不同

时间:2015-08-28 14:37:38

标签: python unit-testing mocking decorator patch

有几次我遇到了unittest.mock.patch装饰器的问题。当我尝试从包含的模块中模拟单个函数时,patch不起作用。但是,如果将包含模块中的函数作为类方法收集,patch可以完美地工作。

部分此question与我的相交。但是这个问题也没有好的答案。

这是我想要描述的一个例子:

|-- __init__.py
|-- helpers.py
|-- main_module.py
|-- tests.py

我在helpers.py中编写了一个函数作为类方法,另一个函数作为单独函数编写:

# helpers.py
class HelperClass():

    def method_a(self):
        return "a"

def function_a():
    return "a"

我已将它们都包含在主模块中:

# main_module.py    
from helpers import HelperClass, function_a


    def function_which_uses_helper_function():
        a_val = function_a()
        return a_val

    def function_which_uses_helper_class_method():
        a_val = HelperClass().method_a()
        return a_val

最后测试:

# tests.py
from unittest import TestCase
from unittest.mock import patch
from main_module import function_which_uses_helper_function, function_which_uses_helper_class_method


class TestClass(TestCase):

    @patch('helpers.function_a')
    def test_function_which_uses_helper_function(self, mock_function_a):
        mock_function_a.return_value = "c"
        self.assertEqual(function_which_uses_helper_function(), "c")

    @patch('helpers.HelperClass.method_a')
    def test_function_which_uses_helper_class_method(self, mock_method_a):
        mock_method_a.return_value = "c"
        self.assertEqual(function_which_uses_helper_class_method(), "c")

这给了我这些结果:

$ py.test tests.py
<...>
tests.py .F
<...>
tests.py:11: in test_function_which_uses_helper_function
    self.assertEqual(function_which_uses_helper_function(), "c")
E   AssertionError: 'a' != 'c'
E   - a
E   + c
============ 1 failed, 1 passed in 0.14 seconds ============

我会感激任何帮助。希望这也有助于某人:)

1 个答案:

答案 0 :(得分:1)

过了一会儿,我终于明白了为什么我的功能范例没有用。解释是herethis article也非常有用。考虑到所有这些解决方案将是:

# main_module.py    
import helpers # <- I had to change my import statement


def function_which_uses_helper_function():
    a_val = helpers.function_a()
    return a_val

def function_which_uses_helper_class_method():
    a_val = helpers.HelperClass().method_a()
    return a_val

另一种解决方案是改变我模拟function_a的方式,即:

from unittest import TestCase
from unittest.mock import patch
from main_module import function_which_uses_helper_function, function_which_uses_helper_class


class TestClass(TestCase):

@patch('main_module.function_a') # <-- !!! I need to mock function in the`main_module`, not in `helpers` !!!
def test_function_which_uses_helper_function(self, mock_function_a):
    mock_function_a.return_value = "c"
    self.assertEqual(function_which_uses_helper_function(), "c")

@patch('helpers.HelperClass.function_a')
def test_function_which_uses_helper_class(self, mock_function_a):
    mock_function_a.return_value = "c"
    self.assertEqual(function_which_uses_helper_class(), "c")

我很遗憾,我最近才意识到这一切。希望这有助于某人:)