求救! python3.7 如何 mock.patch 一个装饰器装饰过的函数??

2021-04-21 20:05:13 +08:00
 0x0208v0

如题: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()


1384 次点击
所在节点    Python
9 条回复
no1xsyzy
2021-04-21 20:18:55 +08:00
标题陈述有误?
你这是在 mock 一个装饰器吧

简单的情况下,你不能。
yyy:timeit():wrap 已经生成并从 yyy:timeit() 里买定离手了。
除非你去魔改 yyy:timeit():wrap 的字节码

当然,如果你高兴的话可以把每一个被 yyy:timeit() 装饰过的函数全部替换为 xxx:mock_timeit() 修饰的版本。
还有一种,就是修改 yyy:timeit() 的实现方式,把它从一个函数转变为一个 class,其中定义了 yyy:timeit.__around__(self, func)(*args, **kwargs) 。
0x0208v0
2021-04-21 20:23:35 +08:00
@no1xsyzy 谢谢大佬!一瞬间我就 get 到点了。但是不知道自己应该怎么用代码写出来:(
aijam
2021-04-22 08:53:34 +08:00
你需要把 decorator 移到另外一个文件里面,比如 zzz.py 。然后
mock.patch("zzz.decorator", mock_timeit).start()
import yyy
no1xsyzy
2021-04-22 09:40:59 +08:00
@aijam 这也算一个思路,但如果在 zzz 中(或者 import zzz 的过程中间接地) import yyy,也会失效

如果能改 yyy 的话,最简单的还是把 yyy 重新以 OO 的方式实现,只需要实现 __init__ 和 __call__
然后 mock timeit.__call__ 就行

不过,我现在看着看着觉得应该是测试粒度有问题
SjwNo1
2021-04-22 10:14:18 +08:00
@no1xsyzy 所以只能 mock 运行时,不能 mock 函数定义时吗
abersheeran
2021-04-22 10:17:50 +08:00
@SjwNo1 不能。import 的时候函数定义的执行就已经完成了。
0x0208v0
2021-04-22 11:34:48 +08:00
@no1xsyzy 确实是,如果想要更好的测试,还是得稍微重构一下代码。
frostming
2021-04-23 15:58:53 +08:00
引用 piglei 的一句话:

每当你发现很难为代码编写测试时,你就应该意识到代码设计可能存在问题

https://www.zlovezl.cn/articles/5-tips-on-unit-testing/
0x0208v0
2021-04-23 19:11:44 +08:00
@frostming 这文章也太棒了,不会是专门为我这个问题写的吧哈哈哈哈哈

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/772268

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX