可以从Python模拟字符串模块吗?

可以从Python模拟字符串模块吗?,python,unittest2,Python,Unittest2,例如,如果我有一个对split方法的调用(例如,一些_string.split(“:”)) 有可能嘲笑这一点。我想声明使用assert_called_once_和调用split函数,我确认您不能这样做,因为split()是str object的内置属性,您不能设置内置或扩展的属性,因为它们是只读的 下面是在尝试Python2.7.10解释器之后的一些非决定性测试 >>> __builtins__.str.split <method 'split' of 'str' obj

例如,如果我有一个对split方法的调用(例如,一些_string.split(“:”))
有可能嘲笑这一点。我想声明使用assert_called_once_和

调用split函数,我确认您不能这样做,因为split()是str object的内置属性,您不能设置内置或扩展的属性,因为它们是只读的

下面是在尝试Python2.7.10解释器之后的一些非决定性测试

>>> __builtins__.str.split
<method 'split' of 'str' objects>
>>> type(__builtins__.str.split)
<type 'method_descriptor'>
>>\uuuuuuuuuuuuuuuuuuuuu.str.split
>>>类型(\uuuu内置\uuuuu.str.split)
尝试使用函数重写它

>>> 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'
>>类型(λf:f)
>>>内置的str.split=lambda f:f
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:无法设置内置/扩展类型“str”的属性
尝试使用可调用(函数或方法)重写它

>类型(可调用)
>>>\uuuu内置\uuuuu.str.split=可调用
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:无法设置内置/扩展类型“str”的属性
在这里更深入地了解了CPython源代码之后[1]。下面的函数列表引入了Objects/typeobject.c中的限制。此函数检查我们是否尝试设置readonly属性并引发TypeError

type_setattro(PyTypeObject*类型、PyObject*名称、PyObject*值)
{
if(!(类型->tp_标志和Py_TPFLAGS_HEAPTYPE)){
Pyrr_格式(
PyExc_类型错误,
“无法设置内置/扩展类型“%s”的属性,
类型->tp_名称);
返回-1;
}
if(PyObject_genericsettr((PyObject*)类型、名称、值)<0)
返回-1;
返回更新槽(类型、名称);
}

[1]

是的,有几个洞。 在我的例子中,我已经成功地在python3中模拟了str,因此我可以断言正在使用特定的输入调用split

有两个洞穴

  • 使用patch,我用继承自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"
    )

这听起来像是一个过于细粒度的测试,只关注错误的细节。为什么不把重点放在单元的输出上呢?我认为对于方法和字符串对象都不能这样做,因为字符串的属性
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"
    )