Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b33b51e

Browse files
authored
Group tests by test case class (#2)
Group tests by test case class
2 parents fa08521 + 4cd2558 commit b33b51e

File tree

3 files changed

+142
-18
lines changed

3 files changed

+142
-18
lines changed

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
bin/
2+
lib/
3+
lib64
4+
include/
5+
*.egg-info/
6+
__pycache__
7+
pyvenv.cfg

codewars_unittest/test_result.py

+15-10
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,45 @@
99

1010

1111
class CodewarsTestResult(unittest.TestResult):
12-
def __init__(self):
12+
def __init__(self, stream):
1313
# Note that we need to avoid super() and use
1414
# super(CodewarsTestResult, self) for Python 2 compatibility
15-
super(CodewarsTestResult, self).__init__()
15+
super(CodewarsTestResult, self).__init__(stream)
16+
self.stream = stream
1617
self.start = 0.0
1718

1819
def startTest(self, test):
1920
desc = test.shortDescription()
2021
if desc is None:
2122
desc = test._testMethodName
22-
print("\n<IT::>" + desc)
23+
self.stream.writeln("\n<IT::>" + desc)
2324
super(CodewarsTestResult, self).startTest(test)
2425
self.start = perf_counter()
2526

2627
def stopTest(self, test):
27-
print("\n<COMPLETEDIN::>{:.4f}".format(1000 * (perf_counter() - self.start)))
28+
self.stream.writeln(
29+
"\n<COMPLETEDIN::>{:.4f}".format(1000 * (perf_counter() - self.start))
30+
)
2831
super(CodewarsTestResult, self).stopTest(test)
2932

3033
def addSuccess(self, test):
31-
print("\n<PASSED::>Test Passed")
34+
self.stream.writeln("\n<PASSED::>Test Passed")
3235
super(CodewarsTestResult, self).addSuccess(test)
3336

3437
def addError(self, test, err):
35-
print("\n<ERROR::>Unhandled Exception")
36-
print(
38+
self.stream.writeln("\n<ERROR::>Unhandled Exception")
39+
self.stream.writeln(
3740
"\n<LOG:ESC:Error>"
3841
+ esc("".join(traceback.format_exception_only(err[0], err[1])))
3942
)
40-
print("\n<LOG:ESC:Traceback>" + esc(self._exc_info_to_string(err, test)))
43+
self.stream.writeln(
44+
"\n<LOG:ESC:Traceback>" + esc(self._exc_info_to_string(err, test))
45+
)
4146
super(CodewarsTestResult, self).addError(test, err)
4247

4348
def addFailure(self, test, err):
44-
print("\n<FAILED::>Test Failed")
45-
print(
49+
self.stream.writeln("\n<FAILED::>Test Failed")
50+
self.stream.writeln(
4651
"\n<LOG:ESC:Failure>"
4752
+ esc("".join(traceback.format_exception_only(err[0], err[1])))
4853
)

codewars_unittest/test_runner.py

+120-8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import sys
2+
import inspect
3+
import unittest
4+
15
# Use timeit.default_timer for Python 2 compatibility.
26
# default_timer is time.perf_counter on 3.3+
37
from timeit import default_timer as perf_counter
@@ -6,16 +10,124 @@
610

711

812
class CodewarsTestRunner(object):
9-
def __init__(self):
10-
pass
13+
def __init__(self, stream=None, group_by_module=False):
14+
if stream is None:
15+
stream = sys.stdout
16+
self.stream = _WritelnDecorator(stream)
17+
self.result = CodewarsTestResult(self.stream)
18+
self.group_by_module = group_by_module
1119

1220
def run(self, test):
13-
r = CodewarsTestResult()
14-
s = perf_counter()
15-
print("\n<DESCRIBE::>Tests")
21+
if isinstance(test, unittest.TestSuite):
22+
self._run_each_test_cases(test)
23+
return self.result
24+
else:
25+
return self._run_case(test)
26+
27+
def _run_each_test_cases(self, suite):
28+
if not isinstance(suite, unittest.TestSuite):
29+
return
30+
31+
for test in suite:
32+
if _is_test_module(test):
33+
name = ""
34+
if self.group_by_module:
35+
case = _get_test_case(test)
36+
name = _get_module_name(case)
37+
if name:
38+
self.stream.writeln(_group(name))
39+
40+
startTime = perf_counter()
41+
for cases in test:
42+
self._run_cases(cases)
43+
44+
if name:
45+
self.stream.writeln(_completedin(startTime, perf_counter()))
46+
else:
47+
self._run_each_test_cases(test)
48+
49+
def _run_cases(self, test):
50+
case = next(iter(test), None)
51+
if not case:
52+
return self.result
53+
54+
self.stream.writeln(_group(_get_class_name(case)))
55+
startTime = perf_counter()
1656
try:
17-
test(r)
57+
test(self.result)
1858
finally:
1959
pass
20-
print("\n<COMPLETEDIN::>{:.4f}".format(1000 * (perf_counter() - s)))
21-
return r
60+
self.stream.writeln(_completedin(startTime, perf_counter()))
61+
return self.result
62+
63+
def _run_case(self, test):
64+
try:
65+
test(self.result)
66+
finally:
67+
pass
68+
return self.result
69+
70+
71+
def _group(name):
72+
return "\n<DESCRIBE::>{}".format(name)
73+
74+
75+
def _completedin(start, end):
76+
return "\n<COMPLETEDIN::>{:.4f}".format(1000 * (end - start))
77+
78+
79+
# True if test suite directly contains a test case
80+
def _is_test_cases(suite):
81+
return isinstance(suite, unittest.TestSuite) and any(
82+
isinstance(t, unittest.TestCase) for t in suite
83+
)
84+
85+
86+
# True if test suite directly contains test cases
87+
def _is_test_module(suite):
88+
return isinstance(suite, unittest.TestSuite) and any(
89+
_is_test_cases(t) for t in suite
90+
)
91+
92+
93+
# Get first test case from a TestSuite created from a test module to find module name
94+
def _get_test_case(suite):
95+
if not isinstance(suite, unittest.TestSuite):
96+
return None
97+
for test in suite:
98+
if not isinstance(test, unittest.TestSuite):
99+
continue
100+
for t in test:
101+
if isinstance(t, unittest.TestCase):
102+
return t
103+
return None
104+
105+
106+
def _get_class_name(x):
107+
cls = x if inspect.isclass(x) else x.__class__
108+
return cls.__name__
109+
110+
111+
def _get_module_name(x):
112+
cls = x if inspect.isclass(x) else x.__class__
113+
mod = cls.__module__
114+
if mod is None or mod == str.__class__.__module__:
115+
return ""
116+
return mod
117+
118+
119+
class _WritelnDecorator(object):
120+
"""Used to decorate file-like objects with a handy 'writeln' method"""
121+
122+
def __init__(self, stream):
123+
self.stream = stream
124+
125+
def __getattr__(self, attr):
126+
if attr in ("stream", "__getstate__"):
127+
raise AttributeError(attr)
128+
return getattr(self.stream, attr)
129+
130+
def writeln(self, arg=None):
131+
if arg:
132+
self.write(arg)
133+
self.write("\n") # text-mode streams translate to \r\n if needed

0 commit comments

Comments
 (0)