Reputation: 1
I have the following code block in my module,
PARSER = argparse.ArgumentParser(description='This script gets ELB statistics '
'and look for any failed instances')
PARSER.add_argument('--profile', help='AWS profile - optional (only if multiple '
'accounts are setup in credentials file)', default='')
PARSER.add_argument('--region', help='AWS region. Defaults to ap-southeast-2',
default='ap-southeast-2')
PARSER.add_argument('--elb', help='DNS Name of the ELB to test', required=True)
PARSER.add_argument('--start', help='Start time of the load test (YYYY-MM-DD HH:MM:SS)',
required=True)
PARSER.add_argument('--end', help='End time of the load test (YYYY-MM-DD HH:MM:SS)',
required=True)
PARSER.add_argument('--debug', help='Print debugging information', action='store_true')
ARGS = PARSER.parse_args()
PROFILE = ARGS.profile
REGION = ARGS.region
ELB = ARGS.elb
START_TIME = format_date_string(ARGS.start)
END_TIME = format_date_string(ARGS.end)
DEBUG = ARGS.debug
if (START_TIME and END_TIME) is not None and START_TIME < END_TIME:
ASG_MON = ASGMonitor(elb_dns_name=ELB, profile_name=PROFILE, region_name=REGION, debug=DEBUG)
# used not keyword so the script exits with status 0 when function returns True (success)
exit(not ASG_MON.analyse_elb_for_failed_nodes(START_TIME, END_TIME))
else:
cprint('Error - Bad start and end date/time input')
exit(1)
I only want to include ASGMonitor class in my unit tests (in the same file). However argparse is causing issues with my tests,
py.test --cov elb_monitoring test --cov-fail-under 80 --cov-report term-missing
And I'm getting the error,
========================================================================================== test session starts ===========================================================================================
platform darwin -- Python 2.7.12, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
rootdir: /Users/achinthag/Documents/Git_Workspace/ea-gatling/elb_monitoring, inifile:
plugins: cov-2.4.0
collected 0 items / 1 errors
---------- coverage: platform darwin, python 2.7.12-final-0 ----------
Name Stmts Miss Cover Missing
-----------------------------------------------------------------
src/elb_monitoring/__init__.py 0 0 100%
src/elb_monitoring/elb_monitor.py 87 65 25% 15-17, 22-26, 35-49, 53-55, 61-70, 74-90, 94-111, 129-142
-----------------------------------------------------------------
TOTAL 87 65 25%
================================================================================================= ERRORS =================================================================================================
_______________________________________________________________________________ ERROR collecting test/test_elb_monitor.py ________________________________________________________________________________
test/test_elb_monitor.py:3: in <module>
from elb_monitoring.elb_monitor import *
src/elb_monitoring/elb_monitor.py:127: in <module>
ARGS = PARSER.parse_args()
/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py:1701: in parse_args
args, argv = self.parse_known_args(args, namespace)
/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py:1733: in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py:1957: in _parse_known_args
self.error(_('argument %s is required') % name)
/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py:2374: in error
self.exit(2, _('%s: error: %s\n') % (self.prog, message))
/usr/local/Cellar/python/2.7.12_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/argparse.py:2362: in exit
_sys.exit(status)
E SystemExit: 2
-------------------------------------------------------------------------------------------- Captured stderr ---------------------------------------------------------------------------------------------
usage: py.test [-h] [--profile PROFILE] [--region REGION] --elb ELB --start
START --end END [--debug]
py.test: error: argument --elb is required
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
======================================================================================== 1 error in 0.61 seconds =========================================================================================
How can I ignore this bit of code from tests?
Thanks,
Upvotes: 0
Views: 1876
Reputation: 140573
You already got good answers, but a more generic piece is missing so far.
The point is: in order to benefit from unit tests; your production code needs to be well organized into independent units. The very first guiding thing here would be the Single Responsibility Principle!
In other words: you don't do everything in one module or one method/function; instead you strive for the opposite of that. You create one class/method/function (that really depends how much OO you want to go for) that isolates the argument handling. You create one class/method/function validating parsed input; and so on.
And then you unit test each of those units separately; isolated from each other.
Upvotes: 1
Reputation: 13552
When you import a module, it gets executed. That's just how python works. Defining a class is actually done when the code for the class is “run”.
So can you define a class and import it, yet skip executing other code? Yes. That's a very common trick, which I was linking earlier. It's done like this:
# everything that needs to be accessed when importing
# for instance, your
class ASGMonitor(object):
# your stuff here
# Th never put your main program code directly
# in the module, create a function for this:
def main():
# put code that must not be run when importing here
# Step 2 : only run main if your module is run directly
# but not if it is imported:
if __name__ == '__main__':
main()
When the module is imported, __name__
is its name. When the module is run directly, it has the special name __main__
, a fact we use at our advantage. The code in your main
function will not be run when importing your module… for instance when you're unit testing your ASGMonitor class.
See this question for a more verbose explanation.
Upvotes: 0
Reputation: 99660
You can extract the parser arguments as a helper method, and handle it accordingly.
def parse_args(args):
PARSER = argparse.ArgumentParser(description='This script gets ELB statistics '
'and look for any failed instances')
PARSER.add_argument('--profile', help='AWS profile - optional (only if multiple '
'accounts are setup in credentials file)', default='')
PARSER.add_argument('--region', help='AWS region. Defaults to ap-southeast-2',
default='ap-southeast-2')
PARSER.add_argument('--elb', help='DNS Name of the ELB to test', required=True)
PARSER.add_argument('--start', help='Start time of the load test (YYYY-MM-DD HH:MM:SS)',
required=True)
PARSER.add_argument('--end', help='End time of the load test (YYYY-MM-DD HH:MM:SS)',
required=True)
PARSER.add_argument('--debug', help='Print debugging information', action='store_true')
parsed_args = PARSER.parse_args()
return parsed_args
def mymethod(ARGS):
PROFILE = ARGS.profile
REGION = ARGS.region
ELB = ARGS.elb
START_TIME = format_date_string(ARGS.start)
END_TIME = format_date_string(ARGS.end)
DEBUG = ARGS.debug
if (START_TIME and END_TIME) is not None and START_TIME < END_TIME:
ASG_MON = ASGMonitor(elb_dns_name=ELB, profile_name=PROFILE, region_name=REGION, debug=DEBUG)
# used not keyword so the script exits with status 0 when function returns True (success)
exit(not ASG_MON.analyse_elb_for_failed_nodes(START_TIME, END_TIME))
else:
cprint('Error - Bad start and end date/time input')
exit(1)
args = parse_args(sys.argv[1:])
mymethod(args)
Now, you can test your mymethod
. Please note that args
to mymethod
is an argsnamespace
object. If you choose to, you can split out the individual elements and send them as arguments into the method.
Upvotes: 2