Skip to content

Commit

Permalink
Merge pull request #95 from elyezer/fix-93
Browse files Browse the repository at this point in the history
Add context parse management
  • Loading branch information
sthirugn committed May 26, 2016
2 parents 9140a08 + 01ce1b9 commit 01a91d8
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 37 deletions.
123 changes: 88 additions & 35 deletions testimony/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ def __init__(self, function_def, parent_class=None, testmodule=None):
self.docstring = ast.get_docstring(function_def)
self.function_def = function_def
self.name = function_def.name
self.parent_class = parent_class
self.testmodule = testmodule
self.parent_class = parent_class.name
self.parent_class_def = parent_class
self.testmodule = testmodule.path
self.module_def = testmodule
self.assertion = None
self.bugs = None
self.feature = None
Expand All @@ -100,17 +102,45 @@ def __init__(self, function_def, parent_class=None, testmodule=None):
self.test = None
self.test_type = None
self.skipped_lines = []
self.unexpected_tags = {}
self._parse_docstring()

def _parse_docstring(self):
"""Parses the test docstring extracting expected values.
def _parse_tags(self, docstring):
"""Parses the docstring and returns the expected tags, unexpected tags
and the docstring lines of the unexpected tags.
If the expected tags is not spelled right they will not be parsed.
"""
if self.docstring is None:
return
For example in the following docstring (using single quote to demo)::
for line in self.docstring.split('@'):
'''First line
@expected_tag1: value
@expected_tag2: value2
@unexpected_tag1: value
@unexpected_tag2: value2
'''
Will return a tuple with the following content::
(
{'expected_tag1': 'value', 'expected_tag2': 'value2'},
{'unexpected_tag1': 'value', 'unexpected_tag2': 'value2'},
['@unexpected_tag1: value', '@unexpected_tag2: value2']
)
"""
valid_tags = [
'assert',
'bz',
'feature',
'setup',
'status',
'steps',
'tags',
'type',
]
expected_tags = {}
unexpected_tags = {}
unexpected_lines = []
for line in docstring.split('@'):
# Remove trailing spaces
line = line.rstrip()
# Sometimes there are double new line
Expand All @@ -121,24 +151,46 @@ def _parse_docstring(self):
tag, value = line.split(':', 1)
tag = tag.lower()
value = value.strip()
if tag == 'assert':
self.assertion = value
elif tag == 'bz':
self.bugs = [bz.strip() for bz in value.split(',')]
elif tag == 'feature':
self.feature = value
elif tag == 'setup':
self.setup = value
elif tag == 'status':
self.status = value
elif tag == 'steps':
self.steps = value
elif tag == 'tags':
self.tags = value
elif tag == 'type':
self.test_type = value
if tag in valid_tags:
if tag == 'bz':
value = [bz.strip() for bz in value.split(',')]
expected_tags[tag] = value
else:
self.skipped_lines.append(line)
unexpected_tags[tag] = value
unexpected_lines.append(line)
return expected_tags, unexpected_tags, unexpected_lines

def _parse_docstring(self):
"""Parses the test docstring extracting expected values.
If the expected tags is not spelled right they will not be parsed.
"""
if self.docstring is None:
return

# Create the contexts
tags, unexpected_tags, _ = self._parse_tags(
ast.get_docstring(self.module_def))
class_tags, class_unexpected_tags, _ = self._parse_tags(
ast.get_docstring(self.parent_class_def))
function_tags, function_unexpected_tags, self.skipped_lines = (
self._parse_tags(self.docstring))

# Update context dictionaries
tags.update(class_tags)
tags.update(function_tags)
unexpected_tags.update(class_unexpected_tags)
unexpected_tags.update(function_unexpected_tags)

for tag, value in tags.items():
if tag == 'bz':
tag = 'bugs'
if tag == 'assert':
tag = 'assertion'
if tag == 'type':
tag = 'test_type'
setattr(self, tag, value)
self.unexpected_tags = unexpected_tags

# Always use the first line of docstring as test case name
if self.test is None:
Expand Down Expand Up @@ -179,7 +231,8 @@ def to_dict(self):
'steps': self.steps,
'tags': self.tags,
'test': self.test,
'test_type': self.test_type
'test_type': self.test_type,
'unexpected-tags': self.unexpected_tags,
}

def __str__(self):
Expand Down Expand Up @@ -513,8 +566,7 @@ def get_testcases(paths):
testmodules = []
for path in paths:
if os.path.isfile(path):
filename = os.path.basename(path)
if is_test_module(filename):
if is_test_module(os.path.basename(path)):
testmodules.append(path)
continue
for dirpath, _, filenames in os.walk(path):
Expand All @@ -525,21 +577,22 @@ def get_testcases(paths):
for testmodule in testmodules:
testcases[testmodule] = []
with open(testmodule) as handler:
for node in ast.iter_child_nodes(ast.parse(handler.read())):
root = ast.parse(handler.read())
root.path = testmodule
for node in ast.iter_child_nodes(root):
if isinstance(node, ast.ClassDef):
# Class test methods
class_name = node.name
testcases[testmodule].extend([
TestFunction(subnode, class_name, testmodule)
TestFunction(subnode, node, root)
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, testmodule=testmodule))
testcases[testmodule].append(
TestFunction(node, testmodule=root)
)
return testcases


Expand Down
12 changes: 12 additions & 0 deletions tests/sample_output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ tests/test_sample.py
TC 1
Test: Login with right credentials
Assert: Login is successful
Setup: Setup Testsample1
Steps: 1. Login to the application with valid credentials
Tags: t1, t2, t3
Skipped lines:
Expand All @@ -20,13 +21,15 @@ TC 2
Test: Login with Latin credentials
Feature: Login - Positive
Assert: Login is successful
Setup: Setup test_positive_login_3
Steps: 1. Login to the application with valid Latin credentials
Tags: t1

TC 3
Test: Login with invalid credentials
Feature: Login - Negative
Assert: Login failed
Setup: Global setup
Steps: 1. Login to the application with valid username and no password


Expand Down Expand Up @@ -57,12 +60,14 @@ TC 1
Test: Login with Credentials having special characters
Feature: Login - Positive
Assert: Activation key is created
Setup: Setup Testsample1
Steps: 1. Login to the application with valid credentials having
special characters
Status: Manual

TC 2
Test: Test missing required docstrings
Setup: Setup Testsample1
Steps: 1. Login to the application with invalid credentials
Bugs: 123456
Status: Manual
Expand All @@ -72,6 +77,7 @@ TC 3
Test: Login with invalid credentials
Feature: Login - Negative
Assert: Login failed
Setup: Global setup
Steps: 1. Login to the application with invalid credentials
Bugs: 123456
Status: Manual
Expand All @@ -89,6 +95,7 @@ tests/test_sample.py
TC 1
Test: Login with right credentials
Assert: Login is successful
Setup: Setup Testsample1
Steps: 1. Login to the application with valid credentials
Tags: t1, t2, t3
Skipped lines:
Expand All @@ -104,19 +111,22 @@ TC 3
Test: Login with Latin credentials
Feature: Login - Positive
Assert: Login is successful
Setup: Setup test_positive_login_3
Steps: 1. Login to the application with valid Latin credentials
Tags: t1

TC 4
Test: Login with Credentials having special characters
Feature: Login - Positive
Assert: Activation key is created
Setup: Setup Testsample1
Steps: 1. Login to the application with valid credentials having
special characters
Status: Manual

TC 5
Test: Test missing required docstrings
Setup: Setup Testsample1
Steps: 1. Login to the application with invalid credentials
Bugs: 123456
Status: Manual
Expand All @@ -126,6 +136,7 @@ TC 6
Test: Login with invalid credentials
Feature: Login - Negative
Assert: Login failed
Setup: Global setup
Steps: 1. Login to the application with invalid credentials
Bugs: 123456
Status: Manual
Expand All @@ -136,6 +147,7 @@ TC 7
Test: Login with invalid credentials
Feature: Login - Negative
Assert: Login failed
Setup: Global setup
Steps: 1. Login to the application with valid username and no password


Expand Down
12 changes: 10 additions & 2 deletions tests/test_sample.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# -*- encoding: utf-8 -*-
"""Test class for Sample Test"""
"""Test class for Sample Test
@Setup: Global setup
"""


class Testsample1():
"""This is a dummy test file used for testing testimony"""
"""This is a dummy test file used for testing testimony
@Setup: Setup Testsample1
"""

# Test with incorrect doctrings:
# Feture vs. Feature, Statues vs. Status,
Expand Down Expand Up @@ -40,6 +46,8 @@ def test_positive_login_2(self):
def test_positive_login_3(self):
"""Login with Latin credentials
@Setup: Setup test_positive_login_3
@Feature: Login - Positive
@Steps:
Expand Down

0 comments on commit 01a91d8

Please sign in to comment.