从内置函数模拟函数 class
Mocking a function from builtin class
是否可以从内置 list
class 模拟一个函数 say append
?
以下似乎不起作用
with patch("my_class.list.append", MagicMock()) as mock_dict:
我不想模拟整个 class,只是一个函数。
我无法控制我正在测试的代码,所以我无法用我自己的代码包装函数。
如果有人能指出正确的方向或一些文档,我将不胜感激。
直接更改内置 class 是不可能的,如果不麻烦的话,请检查 this post 关于 forbiddenfruit
的回购协议。
不过我们当然可以继承内置的方法,然后手动覆盖append
方法。
没有更多细节,我不确定这个最小的工作示例是否能解决您的问题:
class MyList(list):
def append(self, value):
print('Mocked')
class Foo:
var = list()
var_filled = list([5, 6, 7, 8])
mock_foo_var = Foo.var
mock_foo_var = MyList(*mock_foo_var)
mock_foo_var.append(10)
mock_var_filled = Foo.var_filled
mock_var_filled = MyList(mock_var_filled)
mock_var_filled.append(10)
print(mock_foo_var)
print(mock_var_filled)
这将导致输出:
Mocked
Mocked
[]
[5, 6, 7, 8]
请注意,值 10 并未添加,而是用于打印 Mocked
输出。您可以以任何您想要的方式更改此行为。
额外:
也许您确实想要附加一个值,最简单的方法是使用 insert
和 len
def append(self, value):
self.insert(len(self), value)
print('Mocked')
如果这不是您要查找的内容,请使用更多详细信息更新问题。
编辑 1
由于我们现在有了 MyList
的新实例,我们还可以在模块级别更改 list
引用。您不能更改 list
的方法,但可以重命名变量。所以下面的也是可以的:
list = MyList
var = list()
var.append(10)
这将导致输出:
Mocked
如果该引用位于同一个模块中(在调用 list
之前),该引用将起作用。
编辑 2
仔细想想,用例其实没那么简单。在 python 中有 3 种常用的创建列表的方法:
var = list()
var = []
var = list([])
上述方法仅适用于第一种和最后一种情况。
[] = list()
list = MyList
def test_case_1():
var = list()
var.append(10)
print("Passed test 1:", len(var) == 0)
def test_case_2():
var = list([])
var.append(10)
print("Passed test 2:", len(var) == 0)
def test_case_3():
var = list([1, 2, 3])
var.append(10)
print("Passed test 3:", len(var) == 3)
def test_case_4():
var = []
var.append(10)
print("Passed test 4:", len(var) == 0)
def test_case_5():
var = [1, 2, 3]
var.append(10)
print("Passed test 5:", len(var) == 3)
test_case_1()
test_case_2()
test_case_3()
test_case_4()
test_case_5()
将导致输出:
Mocked
Passed test 1: True
Mocked
Passed test 2: True
Mocked
Passed test 3: True
Passed test 4: False
Passed test 5: False
测试用例 4 和 5 的 var
将包含:
[10]
[1, 2, 3, 10]
因此,在使用此解决方案时,所有列表都必须使用 list()
显式创建,并且不能使用 [ ]
列表分配。
如果有人知道如何覆盖 [ ]
函数,我很想知道如何。
我最近发布了一个名为 fishhook 的 python 库,它允许以与 forbiddenfruit 略有不同的方式挂钩方法,这使得它更加稳定,同时还提供了一种调用原始方法的方法实施。
对于 list.append
你可以这样使用它
from fishhook import hook, unhook, orig
@hook(list)
def append(self, item):
print('list.append was called')
return orig(self, item)
要解开该方法,请调用 unhook(list, 'append')
是否可以从内置 list
class 模拟一个函数 say append
?
以下似乎不起作用
with patch("my_class.list.append", MagicMock()) as mock_dict:
我不想模拟整个 class,只是一个函数。
我无法控制我正在测试的代码,所以我无法用我自己的代码包装函数。
如果有人能指出正确的方向或一些文档,我将不胜感激。
直接更改内置 class 是不可能的,如果不麻烦的话,请检查 this post 关于 forbiddenfruit
的回购协议。
不过我们当然可以继承内置的方法,然后手动覆盖append
方法。
没有更多细节,我不确定这个最小的工作示例是否能解决您的问题:
class MyList(list):
def append(self, value):
print('Mocked')
class Foo:
var = list()
var_filled = list([5, 6, 7, 8])
mock_foo_var = Foo.var
mock_foo_var = MyList(*mock_foo_var)
mock_foo_var.append(10)
mock_var_filled = Foo.var_filled
mock_var_filled = MyList(mock_var_filled)
mock_var_filled.append(10)
print(mock_foo_var)
print(mock_var_filled)
这将导致输出:
Mocked
Mocked
[]
[5, 6, 7, 8]
请注意,值 10 并未添加,而是用于打印 Mocked
输出。您可以以任何您想要的方式更改此行为。
额外:
也许您确实想要附加一个值,最简单的方法是使用 insert
和 len
def append(self, value):
self.insert(len(self), value)
print('Mocked')
如果这不是您要查找的内容,请使用更多详细信息更新问题。
编辑 1
由于我们现在有了 MyList
的新实例,我们还可以在模块级别更改 list
引用。您不能更改 list
的方法,但可以重命名变量。所以下面的也是可以的:
list = MyList
var = list()
var.append(10)
这将导致输出:
Mocked
如果该引用位于同一个模块中(在调用 list
之前),该引用将起作用。
编辑 2
仔细想想,用例其实没那么简单。在 python 中有 3 种常用的创建列表的方法:
var = list()
var = []
var = list([])
上述方法仅适用于第一种和最后一种情况。
[] = list()
list = MyList
def test_case_1():
var = list()
var.append(10)
print("Passed test 1:", len(var) == 0)
def test_case_2():
var = list([])
var.append(10)
print("Passed test 2:", len(var) == 0)
def test_case_3():
var = list([1, 2, 3])
var.append(10)
print("Passed test 3:", len(var) == 3)
def test_case_4():
var = []
var.append(10)
print("Passed test 4:", len(var) == 0)
def test_case_5():
var = [1, 2, 3]
var.append(10)
print("Passed test 5:", len(var) == 3)
test_case_1()
test_case_2()
test_case_3()
test_case_4()
test_case_5()
将导致输出:
Mocked
Passed test 1: True
Mocked
Passed test 2: True
Mocked
Passed test 3: True
Passed test 4: False
Passed test 5: False
测试用例 4 和 5 的 var
将包含:
[10]
[1, 2, 3, 10]
因此,在使用此解决方案时,所有列表都必须使用 list()
显式创建,并且不能使用 [ ]
列表分配。
如果有人知道如何覆盖 [ ]
函数,我很想知道如何。
我最近发布了一个名为 fishhook 的 python 库,它允许以与 forbiddenfruit 略有不同的方式挂钩方法,这使得它更加稳定,同时还提供了一种调用原始方法的方法实施。
对于 list.append
你可以这样使用它
from fishhook import hook, unhook, orig
@hook(list)
def append(self, item):
print('list.append was called')
return orig(self, item)
要解开该方法,请调用 unhook(list, 'append')