Reputation: 2439
I have a large project that is unit tested using the Python unittest module.
I have one small method that controls large aspects of the system's behaviour. I need this method to return a fixed result when running under the UTs to give consistent test runs, but it would be expensive for me to mock this out for every single UT.
Is there a way that I can make this single method, unittest aware, so that it can modify its behaviour when running under the unittest?
Upvotes: 46
Views: 19831
Reputation: 2903
Checking for 'unittest' module in sys.modules can result in a false-positive result in case of certain modules used in the code like numpy which loads unittest module.
Depending on the testing framework used, it could be a better idea to look for module from the testing framework. In my case I check for 'nose' module instead of 'unittest' as I execute tests with nosetests:
if 'nose' in sys.modules:
print("during UT - skipping expensive initialization")
else:
print("full initialization")
Upvotes: 0
Reputation: 1514
You can check, if the unittest
module is loaded. It should be loaded only, if a test runs.
>>> 'unittest' in sys.modules.keys()
False
>>> from unittest import TestCase
>>> 'unittest' in sys.modules.keys()
True
Upvotes: 29
Reputation: 2839
With tox
I set an environment variable like this:
[testenv]
setenv = TOX_TESTENV = true
and then in the code I check if the variable is set:
import os
if os.env.get('TOX_TESTENV'):
# Code is running under test.
# This is useful to configure log levels for example.
Upvotes: 3
Reputation: 6935
I don't know much about the unittest
module, but if you're running the file directly for the unit test, you can enclose the test code with the following if:
if __name__ == "__main__":
Any code that lies within that if statement will only be executed if your particular module is being directly invoked, and not imported into something else. According to the docs, that's how you should be calling unittest.main()
in the first place.
https://docs.python.org/2/library/unittest.html
This assumes you're not running from the command line.
EDIT: you could look at the function stack to try and find the unittest.main()
function.
import inspect
def in_unit_test():
current_stack = inspect.stack()
for stack_frame in current_stack:
for program_line in stack_frame[4]: # This element of the stack frame contains
if "unittest" in program_line: # some contextual program lines
return True
return False
https://docs.python.org/2/library/inspect.html
It's kind of a hacky solution, but the inspect
module has a lot of useful functions for introspection.
Upvotes: 6
Reputation: 717
My solution is to set a TEST_FLAG=true
environment variable before running unittest
. For example:
TEST_FLAG=true python -m unittest discover -s tests -b
Then it is just a matter of checking if the variable is set. For example:
MONGODB_URI =
os.environ.get('MONGODB_URI') if not os.environ.get('TEST_FLAG')
else os.environ.get('MONGODB_TEST_URI')
Upvotes: 13
Reputation: 992747
You can modify a function at runtime just for the tests. For example:
def func():
return random.randint()
import module
def replacement_func():
return 4 # chosen by fair dice roll
module.func = replacement_func
# run unit tests here
Now, whenever code in module
calls func()
, then it will actually call back out to your replacement_func()
.
Upvotes: 1
Reputation: 28370
I am sure that there are other, better, methods but you could always set a global flag from your main and not under unit test then access it in your method.
The other way of course would be to override the method as a part of the unit test set-up - if your method is called brian
and you have a test_brian
then simply during your pre-test setting brian = test_brian
will do the job, you may need to put module names into the preceding statement.
Upvotes: 1