Skip to content

Commit fffff9a

Browse files
committed
Improve subtest descriptions.
1 parent c22fef2 commit fffff9a

File tree

2 files changed

+67
-36
lines changed

2 files changed

+67
-36
lines changed

tests/testsuite.py

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ def capture_stdout_stderr():
8383
sys.stderr = orig_stderr
8484

8585

86+
def _strip_xml(xml, changes):
87+
doc = etree.fromstring(xml)
88+
for xpath, attributes in changes.items():
89+
for node in doc.xpath(xpath):
90+
for attrib in node.attrib.keys():
91+
if attrib not in attributes:
92+
del node.attrib[attrib]
93+
return etree.tostring(doc)
94+
95+
8696
class XMLTestRunnerTestCase(unittest.TestCase):
8797
"""
8898
XMLTestRunner test case.
@@ -158,6 +168,11 @@ def test_subTest_error(self):
158168
with self.subTest(i=i):
159169
raise Exception('this is a subtest')
160170

171+
def test_subTest_mixed(self):
172+
for i in range(2):
173+
with self.subTest(i=i):
174+
self.assertLess(i, 1, msg='this is a subtest.')
175+
161176
class DummyErrorInCallTest(unittest.TestCase):
162177

163178
def __call__(self, result):
@@ -220,21 +235,20 @@ def test_classnames(self):
220235
runner.run(suite)
221236
outdir.seek(0)
222237
output = outdir.read()
238+
output = _strip_xml(output, {
239+
'//testsuite': (),
240+
'//testcase': ('classname', 'name'),
241+
'//failure': ('message',),
242+
})
223243
self.assertRegexpMatches(
224244
output,
225-
r'classname="tests\.testsuite\.(XMLTestRunnerTestCase\.)?DummyTest'.encode('utf8'),
226-
)
227-
self.assertRegexpMatches(
228-
output,
229-
r'name="test_pass"'.encode('utf8'),
230-
)
231-
self.assertRegexpMatches(
232-
output,
233-
r'classname="tests\.testsuite\.(XMLTestRunnerTestCase\.)?DummySubTest'.encode('utf8'),
245+
r'classname="tests\.testsuite\.(XMLTestRunnerTestCase\.)?'
246+
r'DummyTest" name="test_pass"'.encode('utf8'),
234247
)
235248
self.assertRegexpMatches(
236249
output,
237-
r'name="test_subTest_pass"'.encode('utf8'),
250+
r'classname="tests\.testsuite\.(XMLTestRunnerTestCase\.)?'
251+
r'DummySubTest" name="test_subTest_pass"'.encode('utf8'),
238252
)
239253

240254
def test_xmlrunner_non_ascii(self):
@@ -423,19 +437,20 @@ def test_unittest_subTest_fail(self):
423437
runner.run(suite)
424438
outdir.seek(0)
425439
output = outdir.read()
440+
output = _strip_xml(output, {
441+
'//testsuite': (),
442+
'//testcase': ('classname', 'name'),
443+
'//failure': ('message',),
444+
})
426445
self.assertRegexpMatches(
427446
output,
428447
br'<testcase classname="tests\.testsuite\.'
429-
br'(XMLTestRunnerTestCase\.)?DummySubTest"')
430-
self.assertRegexpMatches(
431-
output,
448+
br'(XMLTestRunnerTestCase\.)?DummySubTest" '
432449
br'name="test_subTest_fail \(i=0\)"')
433450
self.assertRegexpMatches(
434451
output,
435452
br'<testcase classname="tests\.testsuite\.'
436-
br'(XMLTestRunnerTestCase\.)?DummySubTest"')
437-
self.assertRegexpMatches(
438-
output,
453+
br'(XMLTestRunnerTestCase\.)?DummySubTest" '
439454
br'name="test_subTest_fail \(i=1\)"')
440455

441456
@unittest.skipIf(not hasattr(unittest.TestCase, 'subTest'),
@@ -451,21 +466,48 @@ def test_unittest_subTest_error(self):
451466
runner.run(suite)
452467
outdir.seek(0)
453468
output = outdir.read()
469+
output = _strip_xml(output, {
470+
'//testsuite': (),
471+
'//testcase': ('classname', 'name'),
472+
'//failure': ('message',),
473+
})
454474
self.assertRegexpMatches(
455475
output,
456476
br'<testcase classname="tests\.testsuite\.'
457-
br'(XMLTestRunnerTestCase\.)?DummySubTest"')
458-
self.assertRegexpMatches(
459-
output,
477+
br'(XMLTestRunnerTestCase\.)?DummySubTest" '
460478
br'name="test_subTest_error \(i=0\)"')
461479
self.assertRegexpMatches(
462480
output,
463481
br'<testcase classname="tests\.testsuite\.'
464-
br'(XMLTestRunnerTestCase\.)?DummySubTest"')
465-
self.assertRegexpMatches(
466-
output,
482+
br'(XMLTestRunnerTestCase\.)?DummySubTest" '
467483
br'name="test_subTest_error \(i=1\)"')
468484

485+
486+
@unittest.skipIf(not hasattr(unittest.TestCase, 'subTest'),
487+
'unittest.TestCase.subTest not present.')
488+
def test_unittest_subTest_mixed(self):
489+
# test for issue #155
490+
outdir = BytesIO()
491+
runner = xmlrunner.XMLTestRunner(
492+
stream=self.stream, output=outdir, verbosity=self.verbosity,
493+
**self.runner_kwargs)
494+
suite = unittest.TestSuite()
495+
suite.addTest(self.DummySubTest('test_subTest_mixed'))
496+
runner.run(suite)
497+
outdir.seek(0)
498+
output = outdir.read()
499+
output = _strip_xml(output, {
500+
'//testsuite': (),
501+
'//testcase': ('classname', 'name'),
502+
'//failure': ('message',),
503+
})
504+
self.assertNotIn(
505+
'name="test_subTest_mixed (i=0)"'.encode('utf8'),
506+
output)
507+
self.assertIn(
508+
'name="test_subTest_mixed (i=1)"'.encode('utf8'),
509+
output)
510+
469511
@unittest.skipIf(not hasattr(unittest.TestCase, 'subTest'),
470512
'unittest.TestCase.subTest not present.')
471513
def test_unittest_subTest_pass(self):

xmlrunner/result.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@ def __init__(self, test_result, test_method, outcome=SUCCESS, err=None, subTest=
158158

159159
self.test_name = testcase_name(test_method)
160160
self.test_id = test_method.id()
161-
self.subDescription = None
161+
162162
if subTest:
163163
self.test_id = subTest.id()
164-
self.subDescription = subTest._subDescription()
164+
self.test_description = self.test_result.getDescription(subTest)
165165

166166
self.filename = filename
167167
self.lineno = lineno
@@ -177,17 +177,6 @@ def test_finished(self):
177177
timestamp = datetime.datetime.fromtimestamp(self.test_result.stop_time)
178178
self.timestamp = timestamp.replace(microsecond=0).isoformat()
179179

180-
def get_description(self):
181-
"""
182-
Return a text representation of the test method.
183-
"""
184-
description = self.test_description
185-
186-
if self.subDescription is not None:
187-
description += ' ' + self.subDescription
188-
189-
return description
190-
191180
def get_error_info(self):
192181
"""
193182
Return a text representation of an exception thrown by a test
@@ -440,7 +429,7 @@ def printErrorList(self, flavour, errors):
440429
self.stream.writeln(self.separator1)
441430
self.stream.writeln(
442431
'%s [%.3fs]: %s' % (flavour, test_info.elapsed_time,
443-
test_info.get_description())
432+
test_info.test_description)
444433
)
445434
self.stream.writeln(self.separator2)
446435
self.stream.writeln('%s' % test_info.get_error_info())

0 commit comments

Comments
 (0)