问题
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