summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Szakmeister <john@szakmeister.net>2015-11-28 08:25:43 -0500
committerJohn Szakmeister <john@szakmeister.net>2015-11-28 08:25:43 -0500
commit6d3768e043d44ed95cb5e73de62692653cf88ac5 (patch)
tree8ac409ae2409b7b5a1d184216f2d652b4311b2bf
parentfb4a919f171a80c3381a6408ac16508d91d94a26 (diff)
parentab198aadaeadecd67cab93f283cffb4198636d30 (diff)
downloadnose-6d3768e043d44ed95cb5e73de62692653cf88ac5.tar.gz
Merge pull request #968 from joscha/add-prefix-parameter
Adds option to allow prefixing the class name in an xunit report
-rw-r--r--AUTHORS1
-rw-r--r--README.txt8
-rw-r--r--nose/plugins/xunit.py26
-rw-r--r--unit_tests/test_xunit.py77
4 files changed, 102 insertions, 10 deletions
diff --git a/AUTHORS b/AUTHORS
index 5414bcd..1c29d09 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -25,3 +25,4 @@ Brendan McCollam
Erik Rose
Sascha Peilicke
Andre Caron
+Joscha Feth
diff --git a/README.txt b/README.txt
index e8650e0..de3b748 100644
--- a/README.txt
+++ b/README.txt
@@ -524,6 +524,14 @@ Options
Name of the testsuite in the xunit xml, generated by plugin.
Default test suite name is nosetests.
+--xunit-prefix-with-testsuite-name
+
+ Enables prefixing of the test class name in the xunit xml.
+ This can be used in a matrixed build to distinguish between failures
+ in different environments.
+ If enabled, the testsuite name is used as a prefix.
+ [NOSE_XUNIT_PREFIX_WITH_TESTSUITE_NAME]
+
--all-modules
Enable plugin AllModules: Collect tests from all python modules.
diff --git a/nose/plugins/xunit.py b/nose/plugins/xunit.py
index b43ff04..77e68e3 100644
--- a/nose/plugins/xunit.py
+++ b/nose/plugins/xunit.py
@@ -22,6 +22,12 @@ If you need to change the name or location of the file, you can set the
If you need to change the name of the test suite, you can set the
``--xunit-testsuite-name`` option.
+If you need to prefix the name of the tested classes, you can set the
+``--xunit-prefix-with-testsuite-name`` option.
+This can be used in a matrixed build to distinguish between failures
+in different environments.
+The testsuite name is used as a prefix.
+
Here is an abbreviated version of what an XML test report might look like::
<?xml version="1.0" encoding="UTF-8"?>
@@ -169,6 +175,12 @@ class Xunit(Plugin):
attr = xml_safe(attr)
return saxutils.quoteattr(attr)
+ def _getCls(self, id):
+ if self.xunit_prefix_class:
+ return self._quoteattr('%s.%s' % (self.xunit_testsuite_name, id_split(id)[0]))
+ else:
+ return self._quoteattr(id_split(id)[0])
+
def options(self, parser, env):
"""Sets additional command line options."""
Plugin.options(self, parser, env)
@@ -187,6 +199,13 @@ class Xunit(Plugin):
help=("Name of the testsuite in the xunit xml, generated by plugin. "
"Default test suite name is nosetests."))
+ parser.add_option(
+ '--xunit-prefix-with-testsuite-name', action='store_true',
+ dest='xunit_prefix_class',
+ default=bool(env.get('NOSE_XUNIT_PREFIX_WITH_TESTSUITE_NAME', False)),
+ help=("Whether to prefix the class name under test with testsuite name. "
+ "Defaults to false."))
+
def configure(self, options, config):
"""Configures the xunit plugin."""
Plugin.configure(self, options, config)
@@ -200,6 +219,7 @@ class Xunit(Plugin):
self.errorlist = []
self.error_report_file_name = os.path.realpath(options.xunit_file)
self.xunit_testsuite_name = options.xunit_testsuite_name
+ self.xunit_prefix_class = options.xunit_prefix_class
def report(self, stream):
"""Writes an Xunit-formatted XML file
@@ -292,7 +312,7 @@ class Xunit(Plugin):
u'<testcase classname=%(cls)s name=%(name)s time="%(taken).3f">'
u'<%(type)s type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]>'
u'</%(type)s>%(systemout)s%(systemerr)s</testcase>' %
- {'cls': self._quoteattr(id_split(id)[0]),
+ {'cls': self._getCls(id),
'name': self._quoteattr(id_split(id)[-1]),
'taken': taken,
'type': type,
@@ -315,7 +335,7 @@ class Xunit(Plugin):
u'<testcase classname=%(cls)s name=%(name)s time="%(taken).3f">'
u'<failure type=%(errtype)s message=%(message)s><![CDATA[%(tb)s]]>'
u'</failure>%(systemout)s%(systemerr)s</testcase>' %
- {'cls': self._quoteattr(id_split(id)[0]),
+ {'cls': self._getCls(id),
'name': self._quoteattr(id_split(id)[-1]),
'taken': taken,
'errtype': self._quoteattr(nice_classname(err[0])),
@@ -334,7 +354,7 @@ class Xunit(Plugin):
self.errorlist.append(
'<testcase classname=%(cls)s name=%(name)s '
'time="%(taken).3f">%(systemout)s%(systemerr)s</testcase>' %
- {'cls': self._quoteattr(id_split(id)[0]),
+ {'cls': self._getCls(id),
'name': self._quoteattr(id_split(id)[-1]),
'taken': taken,
'systemout': self._getCapturedStdout(),
diff --git a/unit_tests/test_xunit.py b/unit_tests/test_xunit.py
index dd54b8d..944d285 100644
--- a/unit_tests/test_xunit.py
+++ b/unit_tests/test_xunit.py
@@ -95,19 +95,32 @@ class TestTee(unittest.TestCase):
class TestXMLOutputWithXML(unittest.TestCase):
+ def test_prefix_from_environ(self):
+ parser = optparse.OptionParser()
+ x = Xunit()
+ x.add_options(parser, env={'NOSE_XUNIT_PREFIX_WITH_TESTSUITE_NAME': 'true'})
+ (options, args) = parser.parse_args([])
+ eq_(options.xunit_prefix_class, True)
+
+ def test_prefix_from_opt(self):
+ parser = optparse.OptionParser()
+ x = Xunit()
+ x.add_options(parser, env={})
+ (options, args) = parser.parse_args(["--xunit-prefix-with-testsuite-name"])
+ eq_(options.xunit_prefix_class, True)
+
+class BaseTestXMLOutputWithXML(unittest.TestCase):
+ def configure(self, args):
+ parser = optparse.OptionParser()
+ self.x.add_options(parser, env={})
+ (options, args) = parser.parse_args(args)
+ self.x.configure(options, Config())
def setUp(self):
self.xmlfile = os.path.abspath(
os.path.join(os.path.dirname(__file__),
'support', 'xunit.xml'))
- parser = optparse.OptionParser()
self.x = Xunit()
- self.x.add_options(parser, env={})
- (options, args) = parser.parse_args([
- "--with-xunit",
- "--xunit-file=%s" % self.xmlfile
- ])
- self.x.configure(options, Config())
try:
import xml.etree.ElementTree
@@ -128,6 +141,56 @@ class TestXMLOutputWithXML(unittest.TestCase):
f.close()
return data
+class TestXMLOutputWithXMLAndPrefix(BaseTestXMLOutputWithXML):
+ def setUp(self):
+ super(TestXMLOutputWithXMLAndPrefix, self).setUp()
+
+ def _assert_testcase_classname(self, expected_classname):
+ test = mktest()
+ self.x.beforeTest(test)
+ self.x.addSuccess(test, (None,None,None))
+
+ result = self.get_xml_report()
+ print result
+
+ if self.ET:
+ tree = self.ET.fromstring(result)
+ tc = tree.find("testcase")
+ eq_(tc.attrib['classname'], expected_classname)
+ else:
+ # this is a dumb test for 2.4-
+ assert ('<testcase classname="%s" name="runTest"' % expected_classname) in result
+
+ def test_addSuccess_default(self):
+ self.configure([
+ "--with-xunit",
+ "--xunit-file=%s" % self.xmlfile,
+ "--xunit-prefix-with-testsuite-name"
+ ])
+
+ self._assert_testcase_classname('nosetests.test_xunit.TC')
+
+ def test_addSuccess_custom(self):
+ custom_testsuite_name = 'eartest'
+ self.configure([
+ "--with-xunit",
+ "--xunit-file=%s" % self.xmlfile,
+ "--xunit-testsuite-name=%s" % custom_testsuite_name,
+ "--xunit-prefix-with-testsuite-name"
+ ])
+
+ self._assert_testcase_classname("%s.test_xunit.TC" % custom_testsuite_name)
+
+
+
+class TestXMLOutputWithXML(BaseTestXMLOutputWithXML):
+ def setUp(self):
+ super(TestXMLOutputWithXML, self).setUp()
+ self.configure([
+ "--with-xunit",
+ "--xunit-file=%s" % self.xmlfile
+ ])
+
def test_addFailure(self):
test = mktest()
self.x.beforeTest(test)