How to conditionally patch a unit test in Python?
I'm test a method which makes external API calls which are mocked using a patch
decorator. However, I'd like to be able to set an environment variable, MAKE_EXTERNAL_REQUESTS
, such that if it is truthy, the patch is not applied.
Essentially, I'm looking to something similar to the skipIf
and skipUnless
decorators (cf. https://docs.python.org/3.7/library/unittest.html#skipping-tests-and-expected-failures), but like patchIf
and patchUnless
. As far as I can tell, though, no such functionality is built into patch
. Should I write my own decorator?
python unit-testing python-unittest python-unittest.mock
add a comment |
I'm test a method which makes external API calls which are mocked using a patch
decorator. However, I'd like to be able to set an environment variable, MAKE_EXTERNAL_REQUESTS
, such that if it is truthy, the patch is not applied.
Essentially, I'm looking to something similar to the skipIf
and skipUnless
decorators (cf. https://docs.python.org/3.7/library/unittest.html#skipping-tests-and-expected-failures), but like patchIf
and patchUnless
. As far as I can tell, though, no such functionality is built into patch
. Should I write my own decorator?
python unit-testing python-unittest python-unittest.mock
add a comment |
I'm test a method which makes external API calls which are mocked using a patch
decorator. However, I'd like to be able to set an environment variable, MAKE_EXTERNAL_REQUESTS
, such that if it is truthy, the patch is not applied.
Essentially, I'm looking to something similar to the skipIf
and skipUnless
decorators (cf. https://docs.python.org/3.7/library/unittest.html#skipping-tests-and-expected-failures), but like patchIf
and patchUnless
. As far as I can tell, though, no such functionality is built into patch
. Should I write my own decorator?
python unit-testing python-unittest python-unittest.mock
I'm test a method which makes external API calls which are mocked using a patch
decorator. However, I'd like to be able to set an environment variable, MAKE_EXTERNAL_REQUESTS
, such that if it is truthy, the patch is not applied.
Essentially, I'm looking to something similar to the skipIf
and skipUnless
decorators (cf. https://docs.python.org/3.7/library/unittest.html#skipping-tests-and-expected-failures), but like patchIf
and patchUnless
. As far as I can tell, though, no such functionality is built into patch
. Should I write my own decorator?
python unit-testing python-unittest python-unittest.mock
python unit-testing python-unittest python-unittest.mock
asked Nov 12 '18 at 20:54
Kurt Peek
9,3671968140
9,3671968140
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
You could write your own decorator that checks the environment variable and then calls the regular patch()
if needed. You could also use the wraps
argument in the regular patch()
decorator.
wraps: Item for the mock object to wrap. If wraps is not
None
then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise anAttributeError
).
I think that means you could check the environment variable before setting the return variable in your test. If you don't set a return value, then calls will be passed through to the wrapped object.
add a comment |
You could just manually monkey patch out the dependency you're trying to mock/fake. This is what the patch
decorator is doing under the hood (it also unpatches for you at the end of the function).
def test_something():
original_func = my_module.my_func
if 'MAKE_EXTERNAL_REQUESTS' not in os.environ:
# Monkey patch manually
my_module.my_func = lambda x: x
# do some logic that depends on my_module.my_func
...
# Unpatch
my_module.my_func = original_func
Note that when you assign to the given module attribute you're trying to patch over, that patch is live for the entire session of your interpreter. So if you just patch and don't unpatch, that patch will be live for other tests in your test suite.
If you're doing it one time this might be nice as a quick/dirty solution, if it's many times you might want a decorator to do it.
HTH.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269945%2fhow-to-conditionally-patch-a-unit-test-in-python%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could write your own decorator that checks the environment variable and then calls the regular patch()
if needed. You could also use the wraps
argument in the regular patch()
decorator.
wraps: Item for the mock object to wrap. If wraps is not
None
then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise anAttributeError
).
I think that means you could check the environment variable before setting the return variable in your test. If you don't set a return value, then calls will be passed through to the wrapped object.
add a comment |
You could write your own decorator that checks the environment variable and then calls the regular patch()
if needed. You could also use the wraps
argument in the regular patch()
decorator.
wraps: Item for the mock object to wrap. If wraps is not
None
then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise anAttributeError
).
I think that means you could check the environment variable before setting the return variable in your test. If you don't set a return value, then calls will be passed through to the wrapped object.
add a comment |
You could write your own decorator that checks the environment variable and then calls the regular patch()
if needed. You could also use the wraps
argument in the regular patch()
decorator.
wraps: Item for the mock object to wrap. If wraps is not
None
then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise anAttributeError
).
I think that means you could check the environment variable before setting the return variable in your test. If you don't set a return value, then calls will be passed through to the wrapped object.
You could write your own decorator that checks the environment variable and then calls the regular patch()
if needed. You could also use the wraps
argument in the regular patch()
decorator.
wraps: Item for the mock object to wrap. If wraps is not
None
then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise anAttributeError
).
I think that means you could check the environment variable before setting the return variable in your test. If you don't set a return value, then calls will be passed through to the wrapped object.
answered Nov 14 '18 at 18:18
Don Kirkby
27.3k10127203
27.3k10127203
add a comment |
add a comment |
You could just manually monkey patch out the dependency you're trying to mock/fake. This is what the patch
decorator is doing under the hood (it also unpatches for you at the end of the function).
def test_something():
original_func = my_module.my_func
if 'MAKE_EXTERNAL_REQUESTS' not in os.environ:
# Monkey patch manually
my_module.my_func = lambda x: x
# do some logic that depends on my_module.my_func
...
# Unpatch
my_module.my_func = original_func
Note that when you assign to the given module attribute you're trying to patch over, that patch is live for the entire session of your interpreter. So if you just patch and don't unpatch, that patch will be live for other tests in your test suite.
If you're doing it one time this might be nice as a quick/dirty solution, if it's many times you might want a decorator to do it.
HTH.
add a comment |
You could just manually monkey patch out the dependency you're trying to mock/fake. This is what the patch
decorator is doing under the hood (it also unpatches for you at the end of the function).
def test_something():
original_func = my_module.my_func
if 'MAKE_EXTERNAL_REQUESTS' not in os.environ:
# Monkey patch manually
my_module.my_func = lambda x: x
# do some logic that depends on my_module.my_func
...
# Unpatch
my_module.my_func = original_func
Note that when you assign to the given module attribute you're trying to patch over, that patch is live for the entire session of your interpreter. So if you just patch and don't unpatch, that patch will be live for other tests in your test suite.
If you're doing it one time this might be nice as a quick/dirty solution, if it's many times you might want a decorator to do it.
HTH.
add a comment |
You could just manually monkey patch out the dependency you're trying to mock/fake. This is what the patch
decorator is doing under the hood (it also unpatches for you at the end of the function).
def test_something():
original_func = my_module.my_func
if 'MAKE_EXTERNAL_REQUESTS' not in os.environ:
# Monkey patch manually
my_module.my_func = lambda x: x
# do some logic that depends on my_module.my_func
...
# Unpatch
my_module.my_func = original_func
Note that when you assign to the given module attribute you're trying to patch over, that patch is live for the entire session of your interpreter. So if you just patch and don't unpatch, that patch will be live for other tests in your test suite.
If you're doing it one time this might be nice as a quick/dirty solution, if it's many times you might want a decorator to do it.
HTH.
You could just manually monkey patch out the dependency you're trying to mock/fake. This is what the patch
decorator is doing under the hood (it also unpatches for you at the end of the function).
def test_something():
original_func = my_module.my_func
if 'MAKE_EXTERNAL_REQUESTS' not in os.environ:
# Monkey patch manually
my_module.my_func = lambda x: x
# do some logic that depends on my_module.my_func
...
# Unpatch
my_module.my_func = original_func
Note that when you assign to the given module attribute you're trying to patch over, that patch is live for the entire session of your interpreter. So if you just patch and don't unpatch, that patch will be live for other tests in your test suite.
If you're doing it one time this might be nice as a quick/dirty solution, if it's many times you might want a decorator to do it.
HTH.
edited Nov 14 '18 at 18:35
answered Nov 14 '18 at 18:28
Matt Messersmith
5,98921730
5,98921730
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53269945%2fhow-to-conditionally-patch-a-unit-test-in-python%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown