py3相对import和mock的问题之二
〇、前言
本文主要用于记录问题,很难解决您的实际问题,见谅!
主要介绍博主在mock的时候,一些写法问题导致的bug。技术有限,如果理解错了,欢迎留言,我会及时修改。
本文问题核心:在python3 相对路径import的情况下,mock对应的模块,导致对应模块内其他模块导入错误。
一、问题描述
测试用例结构:
a.py:
# -*- coding: utf-8 -*- import jiliguala def afunc(): print("this func a")
b.py:
# -*- coding: utf-8 -*- from . import a def bfunc(): a.afunc() print("this func b")
core.py:
# -*- coding: utf-8 -*- import unittest import unittest.mock as mock def test_post(x): print("do test http: ", x) @mock.patch.dict("sys.modules", { "test.a": mock.Mock(), }) class TestCore(unittest.TestCase): @mock.patch("a.afunc") def test1(self, test_post): import test.b as b b.bfunc() test_post.side_effect = test_post b.bfunc() @mock.patch("c.cpost") def test2(self, test_post): import test.c as c c.cfunc() test_post.side_effect = test_post c.cHttp()
简单介绍一下,a文件是非py服务(用了一些莫名其妙的模块),b依赖于a,因此我在测试b中的代码需要将a进行隔离。
在core代码中用装饰器的方式,将a模块隔离(from . import a这种写法,在sys.modules中就是test.a的形式),然后重写a.afunc的代码。
好,看代码逻辑,貌似没什么问题。
结果:
我把整个a模块都mock了,怎么还会导入a里面的模块?
写一个空的测试类,看看有没有mock
结果:
成功mock进去了……
问题猜测:估计是我神奇的写法有问题。
没错!如果直接mock那个神奇的模块的话,一点问题没有,但是如果确实有这么一个模块,用到了很多其他py命令行无法调用的模块的话,还是这种写法更好一点。
二、问题的根本原因
这种写法的原理是在sys.modules中加入Mock实例,使得和原来的模块隔离的。
而python的import有个问题:
from a import b。用这个写法的话,会先初始化模块a,然后在a模块中初始化模块b。
测试代码:
from test import d import sys import test print(sys.modules) print(dir(test))
结果:
如图,发生问题的逻辑是:from import的时候,系统环境有对应路径,再import test的时候,会对其中的d进行初始化,导致d里面的东西也会跟着初始化。
所以发生了上面这一幕,我明明把d都给mock了,但是d里面的import还是被执行了。
三、解决方法
对于这种方式,解决方法就是不用from import 或者 直接mock那个奇怪的模块。
主要还是这种写法的问题
四、总结
还是直接mock不用的模块比较好,这方面需要注意写法。
这篇文章在我眼里是不合格的文章,因为博主也看不懂,而且各种问题也没表述清楚……就当做是问题记录吧