如题:python3.7 如何 mock.patch 一个装饰器装饰过的函数??网上有关于如何 mock 装饰器的例子,但是都跑不通。 比如这个例子就不行 https://www.jianshu.com/p/70a0bc3e3dc4
# yyy.py
import functools
def timeit(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
print('timeit')
return func(*args, **kwargs)
return wrap
@timeit
def foo():
print('foo')
# xxx.py
import functools
from unittest import TestCase, main
from unittest import mock
def mock_timeit(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
print('mock timeit')
return func(*args, **kwargs)
return wrap
mock.patch('yyy.timeit', mock_timeit).start()
import yyy
class YYYTestCase(TestCase):
def test_yyy(self):
print(yyy.foo()) # 应该输出 mock timeit
if __name__ == '__main__':
main()
解决方案来了。
首先装饰器必须得用functools.wraps,只有这样被装饰的函数才有__wrapped__(就是原函数) 然后test之前,写这么几句代码。这这这这。。。。。。。:
# xxx.py
import functools
from unittest import TestCase, main
def mock_timeit(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
print('mock timeit')
return func(*args, **kwargs)
return wrap
import yyy
class YYYTestCase(TestCase):
def test_yyy(self):
yyy.foo = mock_timeit(yyy.foo.__wrapped__) ## 手动mock
print(yyy.foo()) # 应该输出 mock timeit
if __name__ == '__main__':
main()
1
no1xsyzy 2021-04-21 20:18:55 +08:00 1
标题陈述有误?
你这是在 mock 一个装饰器吧 简单的情况下,你不能。 yyy:timeit():wrap 已经生成并从 yyy:timeit() 里买定离手了。 除非你去魔改 yyy:timeit():wrap 的字节码 当然,如果你高兴的话可以把每一个被 yyy:timeit() 装饰过的函数全部替换为 xxx:mock_timeit() 修饰的版本。 还有一种,就是修改 yyy:timeit() 的实现方式,把它从一个函数转变为一个 class,其中定义了 yyy:timeit.__around__(self, func)(*args, **kwargs) 。 |
3
aijam 2021-04-22 08:53:34 +08:00 1
|
4
no1xsyzy 2021-04-22 09:40:59 +08:00
@aijam 这也算一个思路,但如果在 zzz 中(或者 import zzz 的过程中间接地) import yyy,也会失效
如果能改 yyy 的话,最简单的还是把 yyy 重新以 OO 的方式实现,只需要实现 __init__ 和 __call__ 然后 mock timeit.__call__ 就行 不过,我现在看着看着觉得应该是测试粒度有问题 |
6
abersheeran 2021-04-22 10:17:50 +08:00 1
@SjwNo1 不能。import 的时候函数定义的执行就已经完成了。
|
8
frostming 2021-04-23 15:58:53 +08:00
引用 piglei 的一句话:
每当你发现很难为代码编写测试时,你就应该意识到代码设计可能存在问题 https://www.zlovezl.cn/articles/5-tips-on-unit-testing/ |