Skip to content

Commit

Permalink
Merge pull request #74 from sthirugn/tags
Browse files Browse the repository at this point in the history
Added support for adding test case tags
  • Loading branch information
elyezer committed Nov 19, 2015
2 parents 08b1af3 + 8159711 commit 0fb41a5
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 14 deletions.
34 changes: 26 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The parameter options are:
4. bugs - Test cases affected by Bugs and the corresponding Bug list
5. manual - List all manual test cases
6. auto - List all auto test cases
7. tags - Prints all test cases with the specified tags

Note:
1. testimony returns a non-zero error code when the test case docstrings does not follow the intended rules, returns zero otherwise
Expand Down Expand Up @@ -66,6 +67,8 @@ Expected Docstring format:

@Status: Manual (REMOVE this field once automated)

@Tags: T1, T2, T3

"""

\3) Optional color formatting - If termcolor package is installed, output will be printed in colored text
Expand All @@ -76,20 +79,24 @@ Usage:
::

$ testimony -h
usage: testimony [-h] [-n] REPORT PATH [PATH ...]
usage: testimony [-h] [-n] [-t TAGS] REPORT PATH [PATH ...]

Inspects and report on the Python test cases.

positional arguments:
REPORT report type, possible values: print, summary,
validate_docstring, bugs, manual, auto
PATH a list of paths to look for tests cases
REPORT report type, possible values: print, summary,
validate_docstring, bugs, manual, auto, tags
PATH a list of paths to look for tests cases

optional arguments:
-h, --help show this help message and exit
-j, --json JSON output
-n, --nocolor Do not use color option

-h, --help show this help message and exit
-j, --json JSON output
-n, --nocolor Do not use color option
-t [TAGS [TAGS ...]], --tags [TAGS [TAGS ...]]
space separated tags to search. Note: Always run this
only in the root of the project where test cases are
stored

::

Expand Down Expand Up @@ -233,6 +240,17 @@ Usage:
$ echo $?
255

::

$ testimony tags tests/ --tag t1
['tests.test_sample.Testsample1.test_positive_login_1',
'tests.test_sample.Testsample1.test_positive_login_3']

$ testimony tags tests/ --tag t1 t2
['tests.test_sample.Testsample1.test_positive_login_1',
'tests.test_sample.Testsample1.test_positive_login_3',
'tests.test_sample.Testsample1.test_negative_login_5']

Success scenario in which testimony returns 0

Expand Down
57 changes: 52 additions & 5 deletions testimony/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from decimal import Decimal
from testimony.constants import (
AUTO_REPORT,
BUGS_REPORT,
CLR_ERR,
CLR_GOOD,
MANUAL_REPORT,
Expand All @@ -24,7 +25,8 @@
PRINT_TC_AFFECTED_BUGS,
PRINT_TOTAL_TC,
SUMMARY_REPORT,
VALIDATE_DOCSTRING_REPORT, BUGS_REPORT,
TAGS_REPORT,
VALIDATE_DOCSTRING_REPORT,
)

try:
Expand Down Expand Up @@ -73,17 +75,19 @@ class TestFunction(object):
#: is not available.
_undefined = object()

def __init__(self, function_def, parent_class=None):
def __init__(self, function_def, parent_class=None, testmodule=None):
#: A ``ast.FunctionDef`` instance used to extract information
self.function_def = function_def
self.parent_class = parent_class
self.docstring = ast.get_docstring(function_def)
self.testmodule = testmodule
self.assertion = None
self.bugs = None
self.feature = None
self.setup = None
self.status = None
self.steps = None
self.tags = None
self.test = None
self.skipped_lines = []
self._parse_docstring()
Expand Down Expand Up @@ -119,6 +123,8 @@ def _parse_docstring(self):
self.status = value
elif tag == 'steps':
self.steps = value
elif tag == 'tags':
self.tags = value
elif tag == 'test':
self.test = value
else:
Expand Down Expand Up @@ -162,6 +168,7 @@ def to_dict(self):
'skipped-lines': self.skipped_lines,
'status': self.status,
'steps': self.steps,
'tags': self.tags,
'test': self.test,
}

Expand Down Expand Up @@ -189,6 +196,8 @@ def __str__(self):
output.append('Bugs: ' + ', '.join(self.bugs))
if self.status is not None:
output.append('Status: ' + self.status)
if self.tags is not None:
output.append('Tags: ' + self.tags)
if self.skipped_lines:
output.append(
'Skipped lines:\n' +
Expand All @@ -204,7 +213,7 @@ def __str__(self):
return '\n'.join(output)


def main(report, paths, json_output, nocolor):
def main(report, paths, json_output, nocolor, tags):
"""Main function for testimony project
Expects a valid report type and valid directory paths, hopefully argparse
Expand All @@ -213,6 +222,7 @@ def main(report, paths, json_output, nocolor):
"""
SETTINGS['json'] = json_output
SETTINGS['nocolor'] = nocolor
SETTINGS['input_tags'] = tags

if report == SUMMARY_REPORT:
report_function = summary_report
Expand All @@ -226,6 +236,8 @@ def main(report, paths, json_output, nocolor):
report_function = manual_report
elif report == AUTO_REPORT:
report_function = auto_report
elif report == TAGS_REPORT:
report_function = tags_report

sys.exit(report_function(get_testcases(paths)))

Expand Down Expand Up @@ -454,6 +466,40 @@ def bugs_report(testcases):
)


def tags_report(testcases):
"""Lists the test cases matching the input tag."""
result = {
'tagged_testcases': [],
}
if not SETTINGS['input_tags']:
print 'Input tags required for this report. See testimony --help'
sys.exit()
# Change the input tags to lower case
input_tags_list = {tag.lower() for tag in SETTINGS['input_tags']}
for _, tests in testcases.items():
for testcase in tests:
if testcase.tags:
testcase_tags_list = {
tag.lower().strip()
for tag in testcase.tags.split(',')
}
# Check if any items in either list match. If so, derive the
# full path of the test case. Expected sample output:
# `tests.test_sample.Testsample1.test_positive_login_1`
if testcase_tags_list.intersection(input_tags_list):
value = testcase.testmodule
if testcase.parent_class:
value = value + '.' + testcase.parent_class
value = value + '.' + testcase.name
value = value.replace('/', '.')
value = value.replace('.py', '', 1)
result['tagged_testcases'].append(value)
if SETTINGS['json']:
print json.dumps(result)
return
print result['tagged_testcases']


def get_testcases(paths):
"""Walk each path in ``paths`` and return the test cases found.
Expand All @@ -475,15 +521,16 @@ def get_testcases(paths):
# Class test methods
class_name = node.name
testcases[testmodule].extend([
TestFunction(subnode, class_name)
TestFunction(subnode, class_name, testmodule)
for subnode in ast.iter_child_nodes(node)
if isinstance(subnode, ast.FunctionDef) and
subnode.name.startswith('test_')
])
elif (isinstance(node, ast.FunctionDef) and
node.name.startswith('test_')):
# Module's test functions
testcases[testmodule].append(TestFunction(node))
testcases[testmodule].append(TestFunction(
node, testmodule=testmodule))
return testcases


Expand Down
9 changes: 8 additions & 1 deletion testimony/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,20 @@ def parse_args():
'-j', '--json', action='store_true', help='JSON output')
parser.add_argument(
'-n', '--nocolor', action='store_true', help='Do not use color option')
parser.add_argument(
'-t',
'--tags',
nargs='*',
help='space separated tags to search. Note: Always run this '
'only in the root of the project where test cases are stored'
)
args = parser.parse_args()
return args


def run(args):
"""Run testimony with given args"""
main(args.report, args.paths, args.json, args.nocolor)
main(args.report, args.paths, args.json, args.nocolor, args.tags)

if __name__ == "__main__":
run(parse_args())
2 changes: 2 additions & 0 deletions testimony/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
BUGS_REPORT = 'bugs'
MANUAL_REPORT = 'manual'
AUTO_REPORT = 'auto'
TAGS_REPORT = 'tags'

REPORT_TAGS = (
PRINT_REPORT,
Expand All @@ -21,6 +22,7 @@
BUGS_REPORT,
MANUAL_REPORT,
AUTO_REPORT,
TAGS_REPORT,
)

PRINT_TOTAL_TC = 'Total Number of test cases: %s'
Expand Down
8 changes: 8 additions & 0 deletions tests/test_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def test_positive_login_1(self):
@Statues: Manual
@Tags: t1, t2, t3
"""
# Code to perform the test
pass
Expand All @@ -45,6 +47,8 @@ def test_positive_login_3(self):
@Assert: Login is successful
@Tags: t1
"""
# Code to perform the test
pass
Expand Down Expand Up @@ -78,6 +82,8 @@ def test_negative_login_5(self):
@Status: Manual
@Tags: t2
"""
# Login to the application

Expand All @@ -102,6 +108,8 @@ def test_negative_login_6(self):
@Status: Manual
@Tags: t3
"""
# Code to perform the test
pass
Expand Down

0 comments on commit 0fb41a5

Please sign in to comment.