是否可以在Python 3.6中模拟内置的len()函数?

Dat*_*Guy 4 python unit-testing mocking python-3.x

可以len()在Python 3.6中模拟内置函数吗?

我有一个类,定义了一个简单的方法,该方法依赖于以下len()功能:

class MyLenFunc(object):
    def is_longer_than_three_characters(self, some_string):
        return len(some_string) > 3
Run Code Online (Sandbox Code Playgroud)

我正在尝试为此方法编写一个单元测试,但是我无法在len()不产生错误的情况下模拟出该函数。这是我到目前为止的内容:

import unittest
from unittest.mock import patch
import my_len_func


class TestMyLenFunc(unittest.TestCase):

    @patch('builtins.len')
    def test_len_function_is_called(self, mock_len):
        # Arrange
        test_string = 'four'

        # Act
        test_object = my_len_func.MyLenFunc()
        test_object.is_longer_than_three_characters(test_string)

        # Assert
        self.assertEqual(1, mock_len.call_count)


if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

我在这里找到了另一个SO问题/答案它暗示不可能模拟出内置函数,因为它们是不可变的。但是,我在这里这里发现了另外两个网站,这表明其他情况。我在上面的单元测试课程中的尝试直接来自这些网站中的后者(是的,我已经尝试了此处提到的其他技术。所有方法都以相同的错误结尾)。

我收到的错误要花很长时间才能发布完整的内容,因此我将剪掉它的重复部分(您将从错误消息的最后一部分中看到它是递归的)。错误文本如下:

ERROR: test_len_function_is_called (__main__.TestMyLenFunc)
---------------------------------------------------------------------- 
Traceback (most recent call last):
    File "C:\Python36\Lib\unittest\mock.py", line 1179, in patched
        return func(*args, **keywargs)
    File "C:/Python/scratchpad/my_len_func_tests.py", line 16, in test_len_function_is_called
        test_object.is_longer_than_three_characters(test_string)
    File "C:\Python\scratchpad\my_len_func.py", line 3, in is_longer_than_three_characters
        return len(some_string) > 3
    File "C:\Python36\Lib\unittest\mock.py", line 939, in __call__
        return _mock_self._mock_call(*args, **kwargs)
    File "C:\Python36\Lib\unittest\mock.py", line 949, in _mock_call
        _call = _Call((args, kwargs), two=True)
    File "C:\Python36\Lib\unittest\mock.py", line 1972, in __new__
        _len = len(value)
    ...
    (Repeat errors from lines 939, 949, and 1972 another 95 times!)
    ...
    File "C:\Python36\Lib\unittest\mock.py", line 939, in __call__
        return _mock_self._mock_call(*args, **kwargs)
    File "C:\Python36\Lib\unittest\mock.py", line 944, in _mock_call
        self.called = True RecursionError: maximum recursion depth exceeded while calling a Python object

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (errors=1)
Run Code Online (Sandbox Code Playgroud)

提前谢谢了。

Mar*_*ers 7

不要打补丁builtins.len; 现在的代码mock图书馆休息,因为它需要正常操作功能!修补被测模块的全局变量:

@patch('my_len_func.len')
Run Code Online (Sandbox Code Playgroud)

会将全局变量添加len到您的模块中,len(some_string)in MyLenFunc().is_longer_than_three_characters()方法将找到该全局变量,而不是内置函数。

但是,我必须说,测试if len()的感觉是错误的测试。您想检查该方法是否能为给定的输入产生正确的结果,诸如基本操作之类的len()目标只是实现该目标的小组成部分,通常不会在该范围内进行测试。

  • 非常感谢。这种方法效果很好。我完全同意测试 `len()` 是否被调用是错误的。这只是我正在处理的实际问题的一个简化示例,它恰好说明了我遇到的问题。 (3认同)