py3相对import和mock的问题

〇、前言

  本文用于记录博主用自己的方法编写mock的时候,与py3相对import的机制发生问题的情况

一、问题描述

  情境:

    我想测试view_b的代码,但是view_b依赖view_a,为了测试,我要隔离view_a

  代码结构:

    

  代码:

  view_a.py:

import jiliguala

def viewfunca():
    print("do view a")

  view_b.py:

from . import view_a

def viewfuncb():
    view_a.viewfunca()
    print("do view b")

  test_core2.py:

# -*- coding: utf-8 -*-

import sys
import unittest
import unittest.mock as mock

@mock.patch.dict("sys.modules", {
    "test.view.view_a": mock.Mock(),
})
class TestCore(unittest.TestCase):
    @mock.patch("test.view.view_a")
    def test1(self, oMockViewa):
        def funca():
            print("do mock a")
        from test.view import view_b
        oMockViewa.side_effect = funca
        print()
        view_b.viewfuncb()

    def test2(self):
        print(sys.modules)

  在pycharm中用unittest运行test1之后出现问题

File "D:python 3.6.7libunittestmock.py", line 1217, in get_original "%s does not have the attribute %r" % (target, name)
AttributeError: <module 'test.view' from 'E:\game_box\test\view\__init__.py'> does not have the attribute 'view_a'

  问题描述:

    我隔离了view_a,为什么告诉我初始化view_a的时候出错了?哪里的初始化?

二、原因分析

  如果通过删删减减做过几次实验,会发现,如果把test1的装饰器去了,这个就不报错了(代码要改一下)。

  那么可以确认问题,问题出在这条语句上。

  运行test2:

  

  分析:

  1、代码中用于mock的类装饰器的原理是,在系统变量中,加入对应的路径。(从test_core2的test2中可以测试)

  2、mock.patch是对环境中的test内的view内的view_a,进行mock

  概括一下就是:我虽然在系统变量里加了test.view.view.a,但是我没有【加入test,以及在test里面加入view,在view加入view_a】这个操作。

  

  但是仔细看代码

  b.py代码中用了from . import view_a这句话,应该做了之前说的那个初始化操作,为什么没有?

  原因:py3中import的执行策略,如果在系统路径中检测到这个路径,直接返回,不会进行初始化操作

    这是py代码的优化,但是这个优化,坑了这种mock写法……

  验证方法:

    python import源码

    这个是python __import__函数的源码:

    

    应该很容易理解,所以这种mock写法,会导致父模块没有被初始化

三、解决方法

  1、如果是py2环境,不要用相对导入,直接import

  2、在__init__.py中对添加view_a的接口

  3、如果不嫌麻烦,不要隔离view_a,可以隔离更具体的接口,比如view_a中的【jiliguala】这种必须隔离的模块(因为不隔离就会报错)

  4、换种mock写法,在此不提供了

四、总结

  用装饰器写mock,而且直接mock掉想隔离的模块很方便,但是找bug很麻烦。

  这里也是感谢某位师兄翻看python源码帮我解决了这个bug(这个不看源码很难找到,因为这种优化不会写文档里面)

  

原文地址:https://www.cnblogs.com/end-emptiness/p/12111098.html