Python: mock patch a module wherever it is imported from

流过昼夜 提交于 2019-12-06 07:33:46

问题


I need to make sure that running unit tests won't trigger calling a heavy outer world function, say, this one:

# bigbad.py
def request(param):
    return 'I searched the whole Internet for "{}"'.format(param)

Multiple modules use this function (bigbad.request) and they import it differently (in real-life it may be imported from an external library as well). Say, there are two modules, a and b, where b depends on a and both use the function:

# a.py, from...import
from bigbad import request

def routine_a():
    return request('a')

# b.py, imports directly
import a
import bigbad

def routine_b():
    resp_a = a.routine_a()
    return 'resp_a: {}, resp_b=request(resp_a): {}'.format(resp_a, bigbad.request(resp_a))

Is there a way to make sure that bigbad.request is not ever called? This code mocks only one of the imports:

# test_b.py
import unittest
from unittest import mock
import b

with mock.patch('bigbad.request') as mock_request:
    mock_request.return_value = 'mocked'
    print(b.routine_b())

Obviously I could refactor b and change the imports but this way I cannot guarantee that someone during the future development is not going to break this provision. I believe tests should test behaviour than implementation details.


回答1:


import bigbad
bigbad.request = # some dummy function

This will work as long as it runs before any module that does from bigbad import request is run/imported. That is, as long as they run after, they will receive the dummy function.




回答2:


# a.py, from...import
from bigbad import request

To ensure that the original request is never called, you'll have to patch all the places where the reference is imported:

import mock
with mock.patch('a.request', return_value='mocked') as mock_request:
    ...

This is tedious, so if possible don't do from bigbad import request in your code, but use import bigbad; bigbad.request.

Another solution: if possible, change bigbad.py:

# bigbad.py
def _request(param):
    return 'I searched the whole Internet for "{}"'.format(param)


def request(param):
    return _request(param)

Then, even if some code does from bigbad import request, you'd be able to do with mock.patch('bigbad._request', return_value='mocked') as mock_request:.



来源:https://stackoverflow.com/questions/37297265/python-mock-patch-a-module-wherever-it-is-imported-from

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!