1

例如,如果我调用了 split 方法(即 some_string.split(":") ),则可以模拟它。我想断言 split 函数是使用 assert_called_once_with 调用的

4

2 回答 2

3

我确认您不能这样做,因为 split() 是 str 对象的内置属性,并且您不能设置内置或扩展的属性,因为它们是只读的。

在尝试使用 Python 2.7.10 解释器后,下面的一些不确定的测试

>>> __builtins__.str.split
<method 'split' of 'str' objects>
>>> type(__builtins__.str.split)
<type 'method_descriptor'>

尝试使用函数覆盖它

>>> type(lambda f:f)
<type 'function'>
>>> __builtins__.str.split = lambda f: f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'

尝试使用可调用(函数或方法)覆盖它

>>> type(callable)
<type 'builtin_function_or_method'>
>>> __builtins__.str.split = callable
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'

在此处 [1] 更深入地查看了 CPython 源代码之后。这是Objects/typeobject.c中的一个限制,由下面的函数列表介绍。此函数检查我们是否尝试设置只读属性并引发 TypeError。

    type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
    if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
        PyErr_Format(
            PyExc_TypeError,
            "can't set attributes of built-in/extension type '%s'",
            type->tp_name);
        return -1;
    }
    if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
        return -1;
    return update_slot(type, name);
}

[1] https://hg.python.org/cpython/file/tip/Objects/typeobject.c#l3022

于 2015-10-30T03:09:10.257 回答
0

是的,它带有一些鱼子酱。就我而言,我已经成功地在 python3 中模拟了 str ,因此我可以断言 split 正在使用特定输入调用

有两种鱼子酱

  • 使用补丁,我用一个继承自 str 的新类替换了原来的 str 类
  • 在我正在测试的代码中,我必须做一个冗余的字符串转换,比如str(str_val).split

以下是如何做到这一点:

class MyStr(str):
    def split(self, sep=None, maxsplit=-1)):
        expected_str = "some_input_mutated_inside_fn_before_split_called"
        self.assertEqual(self, expected_str)
        return super().split(sep=sep, maxsplit=maxsplit)

with patch('mymodule.str', new=MyStr):
    output = mymodule.function_that_calls_string_split(
        "some_input"
    )
于 2020-09-19T00:22:28.017 回答