junit-xml-1.6/0000755000076500000240000000000012547631404013023 5ustar bbstaff00000000000000junit-xml-1.6/junit_xml/0000755000076500000240000000000012547631404015034 5ustar bbstaff00000000000000junit-xml-1.6/junit_xml/__init__.py0000644000076500000240000002755312547631326017164 0ustar bbstaff00000000000000#!/usr/bin/env python # -*- coding: UTF-8 -*- from collections import defaultdict import sys import re import xml.etree.ElementTree as ET import xml.dom.minidom from six import u, iteritems, PY2 try: # Python 2 unichr except NameError: # pragma: nocover # Python 3 unichr = chr """ Based on the understanding of what Jenkins can parse for JUnit XML files. the output of the testcase the output of the testcase the output of the testcase I am system output I am the error output """ def decode(var, encoding): ''' If not already unicode, decode it. ''' if PY2: if isinstance(var, unicode): ret = var elif isinstance(var, str): if encoding: ret = var.decode(encoding) else: ret = unicode(var) else: ret = unicode(var) else: ret = str(var) return ret class TestSuite(object): '''Suite of test cases. Can handle unicode strings or binary strings if their encoding is provided. ''' def __init__(self, name, test_cases=None, hostname=None, id=None, package=None, timestamp=None, properties=None): self.name = name if not test_cases: test_cases = [] try: iter(test_cases) except TypeError: raise Exception('test_cases must be a list of test cases') self.test_cases = test_cases self.hostname = hostname self.id = id self.package = package self.timestamp = timestamp self.properties = properties def build_xml_doc(self, encoding=None): ''' Builds the XML document for the JUnit test suite. Produces clean unicode strings and decodes non-unicode with the help of encoding. @param encoding: Used to decode encoded strings. @return: XML document with unicode string elements ''' # build the test suite element test_suite_attributes = dict() test_suite_attributes['name'] = decode(self.name, encoding) test_suite_attributes['failures'] = \ str(len([c for c in self.test_cases if c.is_failure()])) test_suite_attributes['errors'] = \ str(len([c for c in self.test_cases if c.is_error()])) test_suite_attributes['skipped'] = \ str(len([c for c in self.test_cases if c.is_skipped()])) test_suite_attributes['time'] = \ str(sum(c.elapsed_sec for c in self.test_cases if c.elapsed_sec)) test_suite_attributes['tests'] = str(len(self.test_cases)) if self.hostname: test_suite_attributes['hostname'] = decode(self.hostname, encoding) if self.id: test_suite_attributes['id'] = decode(self.id, encoding) if self.package: test_suite_attributes['package'] = decode(self.package, encoding) if self.timestamp: test_suite_attributes['timestamp'] = decode(self.timestamp, encoding) xml_element = ET.Element("testsuite", test_suite_attributes) # add any properties if self.properties: props_element = ET.SubElement(xml_element, "properties") for k, v in self.properties.items(): attrs = {'name': decode(k, encoding), 'value': decode(v, encoding)} ET.SubElement(props_element, "property", attrs) # test cases for case in self.test_cases: test_case_attributes = dict() test_case_attributes['name'] = decode(case.name, encoding) if case.elapsed_sec: test_case_attributes['time'] = "%f" % case.elapsed_sec if case.classname: test_case_attributes['classname'] = decode(case.classname, encoding) test_case_element = ET.SubElement( xml_element, "testcase", test_case_attributes) # failures if case.is_failure(): attrs = {'type': 'failure'} if case.failure_message: attrs['message'] = decode(case.failure_message, encoding) failure_element = ET.Element("failure", attrs) if case.failure_output: failure_element.text = decode(case.failure_output, encoding) test_case_element.append(failure_element) # errors if case.is_error(): attrs = {'type': 'error'} if case.error_message: attrs['message'] = decode(case.error_message, encoding) error_element = ET.Element("error", attrs) if case.error_output: error_element.text = decode(case.error_output, encoding) test_case_element.append(error_element) # skippeds if case.is_skipped(): attrs = {'type': 'skipped'} if case.skipped_message: attrs['message'] = decode(case.skipped_message, encoding) skipped_element = ET.Element("skipped", attrs) if case.skipped_output: skipped_element.text = decode(case.skipped_output, encoding) test_case_element.append(skipped_element) # test stdout if case.stdout: stdout_element = ET.Element("system-out") stdout_element.text = decode(case.stdout, encoding) test_case_element.append(stdout_element) # test stderr if case.stderr: stderr_element = ET.Element("system-err") stderr_element.text = decode(case.stderr, encoding) test_case_element.append(stderr_element) return xml_element @staticmethod def to_xml_string(test_suites, prettyprint=True, encoding=None): '''Returns the string representation of the JUnit XML document. @param encoding: The encoding of the input. @return: unicode string ''' try: iter(test_suites) except TypeError: raise Exception('test_suites must be a list of test suites') xml_element = ET.Element("testsuites") attributes = defaultdict(int) for ts in test_suites: ts_xml = ts.build_xml_doc(encoding=encoding) for key in ['failures', 'errors', 'skipped', 'tests']: attributes[key] += int(ts_xml.get(key, 0)) for key in ['time']: attributes[key] += float(ts_xml.get(key, 0)) xml_element.append(ts_xml) for key, value in iteritems(attributes): xml_element.set(key, str(value)) xml_string = ET.tostring(xml_element, encoding=encoding) # is encoded now xml_string = TestSuite._clean_illegal_xml_chars( xml_string.decode(encoding or 'utf-8')) # is unicode now if prettyprint: # minidom.parseString() works just on correctly encoded binary strings xml_string = xml_string.encode(encoding or 'utf-8') xml_string = xml.dom.minidom.parseString(xml_string) # toprettyxml() produces unicode if no encoding is being passed or binary string with an encoding xml_string = xml_string.toprettyxml(encoding=encoding) if encoding: xml_string = xml_string.decode(encoding) # is unicode now return xml_string @staticmethod def to_file(file_descriptor, test_suites, prettyprint=True, encoding=None): ''' Writes the JUnit XML document to a file. ''' xml_string = TestSuite.to_xml_string( test_suites, prettyprint=prettyprint, encoding=encoding) # has problems with encoded str with non-ASCII (non-default-encoding) characters! file_descriptor.write(xml_string) @staticmethod def _clean_illegal_xml_chars(string_to_clean): ''' Removes any illegal unicode characters from the given XML string. @see: http://stackoverflow.com/questions/1707890/fast-way-to-filter-illegal-xml-unicode-chars-in-python ''' illegal_unichrs = [ (0x00, 0x08), (0x0B, 0x1F), (0x7F, 0x84), (0x86, 0x9F), (0xD800, 0xDFFF), (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF), (0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF)] illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) for (low, high) in illegal_unichrs if low < sys.maxunicode] illegal_xml_re = re.compile(u('[%s]') % u('').join(illegal_ranges)) return illegal_xml_re.sub('', string_to_clean) class TestCase(object): """A JUnit test case with a result and possibly some stdout or stderr""" def __init__(self, name, classname=None, elapsed_sec=None, stdout=None, stderr=None): self.name = name self.elapsed_sec = elapsed_sec self.stdout = stdout self.stderr = stderr self.classname = classname self.error_message = None self.error_output = None self.failure_message = None self.failure_output = None self.skipped_message = None self.skipped_output = None def add_error_info(self, message=None, output=None): """Adds an error message, output, or both to the test case""" if message: self.error_message = message if output: self.error_output = output def add_failure_info(self, message=None, output=None): """Adds a failure message, output, or both to the test case""" if message: self.failure_message = message if output: self.failure_output = output def add_skipped_info(self, message=None, output=None): """Adds a skipped message, output, or both to the test case""" if message: self.skipped_message = message if output: self.skipped_output = output def is_failure(self): """returns true if this test case is a failure""" return self.failure_output or self.failure_message def is_error(self): """returns true if this test case is an error""" return self.error_output or self.error_message def is_skipped(self): """returns true if this test case has been skipped""" return self.skipped_output or self.skipped_message junit-xml-1.6/junit_xml.egg-info/0000755000076500000240000000000012547631404016526 5ustar bbstaff00000000000000junit-xml-1.6/junit_xml.egg-info/dependency_links.txt0000644000076500000240000000000112547631404022574 0ustar bbstaff00000000000000 junit-xml-1.6/junit_xml.egg-info/PKG-INFO0000644000076500000240000000737212547631404017634 0ustar bbstaff00000000000000Metadata-Version: 1.1 Name: junit-xml Version: 1.6 Summary: Creates JUnit XML test result documents that can be read by tools such as Jenkins Home-page: https://github.com/kyrus/python-junit-xml Author: Brian Beyer Author-email: brian@kyr.us License: MIT Description: python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Freely Distributable Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: Software Development :: Testing junit-xml-1.6/junit_xml.egg-info/requires.txt0000644000076500000240000000000312547631404021117 0ustar bbstaff00000000000000sixjunit-xml-1.6/junit_xml.egg-info/SOURCES.txt0000644000076500000240000000037712547631404020421 0ustar bbstaff00000000000000LICENSE.txt MANIFEST.in README.rst setup.py test_junit_xml.py tox.ini junit_xml/__init__.py junit_xml.egg-info/PKG-INFO junit_xml.egg-info/SOURCES.txt junit_xml.egg-info/dependency_links.txt junit_xml.egg-info/requires.txt junit_xml.egg-info/top_level.txtjunit-xml-1.6/junit_xml.egg-info/top_level.txt0000644000076500000240000000001212547631404021251 0ustar bbstaff00000000000000junit_xml junit-xml-1.6/LICENSE.txt0000644000076500000240000000210112547631326014643 0ustar bbstaff00000000000000The MIT License Copyright (c) 2013 Kyrus Tech, Inc., Brian Beyer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.junit-xml-1.6/MANIFEST.in0000644000076500000240000000014212547631326014561 0ustar bbstaff00000000000000include LICENSE.txt include README.rst include setup.py include test_junit_xml.py include tox.ini junit-xml-1.6/PKG-INFO0000644000076500000240000000737212547631404014131 0ustar bbstaff00000000000000Metadata-Version: 1.1 Name: junit-xml Version: 1.6 Summary: Creates JUnit XML test result documents that can be read by tools such as Jenkins Home-page: https://github.com/kyrus/python-junit-xml Author: Brian Beyer Author-email: brian@kyr.us License: MIT Description: python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: Freely Distributable Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Build Tools Classifier: Topic :: Software Development :: Testing junit-xml-1.6/README.rst0000644000076500000240000000452012547631326014516 0ustar bbstaff00000000000000python-junit-xml ================ .. image:: https://travis-ci.org/kyrus/python-junit-xml.png?branch=master About ----- A Python module for creating JUnit XML test result documents that can be read by tools such as Jenkins. If you are ever working with test tool or test suite written in Python and want to take advantage of Jenkins' pretty graphs and test reporting capabilities, this module will let you generate the XML test reports. *As there is no definitive Jenkins JUnit XSD that I could find, the XML documents created by this module support a schema based on Google searches and the Jenkins JUnit XML reader source code. File a bug if something doesn't work like you expect it to.* Installation ------------ Install using pip or easy_install: :: pip install junit-xml or easy_install junit-xml You can also clone the Git repository from Github and install it manually: :: git clone https://github.com/kyrus/python-junit-xml.git python setup.py install Using ----- Create a test suite, add a test case, and print it to the screen: .. code-block:: python from junit_xml import TestSuite, TestCase test_cases = [TestCase('Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')] ts = TestSuite("my test suite", test_cases) # pretty printing is on by default but can be disabled using prettyprint=False print(TestSuite.to_xml_string([ts])) Produces the following output .. code-block:: xml I am stdout! I am stderr! Writing XML to a file: .. code-block:: python # you can also write the XML to a file and not pretty print it with open('output.xml', 'w') as f: TestSuite.to_file(f, [ts], prettyprint=False) See the docs and unit tests for more examples. NOTE: Unicode characters identified as "illegal or discouraged" are automatically stripped from the XML string or file. Running the tests ----------------- :: # activate your virtualenv pip install tox tox junit-xml-1.6/setup.cfg0000644000076500000240000000007312547631404014644 0ustar bbstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 junit-xml-1.6/setup.py0000644000076500000240000000207612547631352014544 0ustar bbstaff00000000000000#!/usr/bin/env python from setuptools import setup, find_packages import os def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup( name='junit-xml', author='Brian Beyer', author_email='brian@kyr.us', url='https://github.com/kyrus/python-junit-xml', license='MIT', packages=find_packages(), test_suite='test_junit_xml', description='Creates JUnit XML test result documents that can be read by ' 'tools such as Jenkins', long_description=read('README.rst'), version='1.6', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: Freely Distributable', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Build Tools', 'Topic :: Software Development :: Testing', ], install_requires=[ 'six' ] ) junit-xml-1.6/test_junit_xml.py0000644000076500000240000004655012547631326016462 0ustar bbstaff00000000000000# -*- coding: UTF-8 -*- from __future__ import with_statement import unittest import os import tempfile import textwrap from xml.dom import minidom import codecs from six import u, PY2 from junit_xml import TestCase, TestSuite, decode def serialize_and_read(test_suites, to_file=False, prettyprint=False, encoding=None): """writes the test suite to an XML string and then re-reads it using minidom, returning => (test suite element, list of test case elements)""" try: iter(test_suites) except TypeError: test_suites = [test_suites] if to_file: fd, filename = tempfile.mkstemp(text=True) os.close(fd) with codecs.open(filename, mode='w', encoding=encoding) as f: TestSuite.to_file(f, test_suites, prettyprint=prettyprint, encoding=encoding) print("Serialized XML to temp file [%s]" % filename) xmldoc = minidom.parse(filename) os.remove(filename) else: xml_string = TestSuite.to_xml_string( test_suites, prettyprint=prettyprint, encoding=encoding) if PY2: assert isinstance(xml_string, unicode) print("Serialized XML to string:\n%s" % xml_string) if encoding: xml_string = xml_string.encode(encoding) xmldoc = minidom.parseString(xml_string) def remove_blanks(node): for x in node.childNodes: if x.nodeType == minidom.Node.TEXT_NODE: if x.nodeValue: x.nodeValue = x.nodeValue.strip() elif x.nodeType == minidom.Node.ELEMENT_NODE: remove_blanks(x) remove_blanks(xmldoc) xmldoc.normalize() ret = [] suites = xmldoc.getElementsByTagName("testsuites")[0] for suite in suites.getElementsByTagName("testsuite"): cases = suite.getElementsByTagName("testcase") ret.append((suite, cases)) return ret class TestSuiteTests(unittest.TestCase): def test_single_suite_single_test_case(self): try: (ts, tcs) = serialize_and_read( TestSuite('test', TestCase('Test1')), to_file=True)[0] self.fail("This should've raised an exeception") # pragma: nocover except Exception as exc: self.assertEqual( str(exc), 'test_cases must be a list of test cases') def test_single_suite_no_test_cases(self): properties = {'foo': 'bar'} package = 'mypackage' timestamp = 1398382805 (ts, tcs) = serialize_and_read( TestSuite( 'test', [], hostname='localhost', id=1, properties=properties, package=package, timestamp=timestamp ), to_file=True, prettyprint=True )[0] self.assertEqual(ts.tagName, 'testsuite') self.assertEqual(ts.attributes['package'].value, package) self.assertEqual(ts.attributes['timestamp'].value, str(timestamp)) self.assertEqual( ts.childNodes[0].childNodes[0].attributes['name'].value, 'foo') self.assertEqual( ts.childNodes[0].childNodes[0].attributes['value'].value, 'bar') def test_single_suite_no_test_cases_utf8(self): properties = {'foö': 'bär'} package = 'mypäckage' timestamp = 1398382805 test_suite = TestSuite( 'äöü', [], hostname='löcalhost', id='äöü', properties=properties, package=package, timestamp=timestamp ) (ts, tcs) = serialize_and_read( test_suite, to_file=True, prettyprint=True, encoding='utf-8' )[0] self.assertEqual(ts.tagName, 'testsuite') self.assertEqual(ts.attributes['package'].value, decode(package, 'utf-8')) self.assertEqual(ts.attributes['timestamp'].value, str(timestamp)) self.assertEqual( ts.childNodes[0].childNodes[0].attributes['name'].value, decode('foö', 'utf-8')) self.assertEqual( ts.childNodes[0].childNodes[0].attributes['value'].value, decode('bär', 'utf-8')) def test_single_suite_no_test_cases_unicode(self): properties = {decode('foö', 'utf-8'): decode('bär', 'utf-8')} package = decode('mypäckage', 'utf-8') timestamp = 1398382805 (ts, tcs) = serialize_and_read( TestSuite( decode('äöü', 'utf-8'), [], hostname=decode('löcalhost', 'utf-8'), id=decode('äöü', 'utf-8'), properties=properties, package=package, timestamp=timestamp ), to_file=True, prettyprint=True, encoding='utf-8' )[0] self.assertEqual(ts.tagName, 'testsuite') self.assertEqual(ts.attributes['package'].value, package) self.assertEqual(ts.attributes['timestamp'].value, str(timestamp)) self.assertEqual( ts.childNodes[0].childNodes[0].attributes['name'].value, decode('foö', 'utf-8')) self.assertEqual( ts.childNodes[0].childNodes[0].attributes['value'].value, decode('bär', 'utf-8')) def test_single_suite_to_file(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1')]), to_file=True)[0] verify_test_case(self, tcs[0], {'name': 'Test1'}) def test_single_suite_to_file_prettyprint(self): (ts, tcs) = serialize_and_read(TestSuite( 'test', [TestCase('Test1')]), to_file=True, prettyprint=True)[0] verify_test_case(self, tcs[0], {'name': 'Test1'}) def test_single_suite_prettyprint(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1')]), to_file=False, prettyprint=True)[0] verify_test_case(self, tcs[0], {'name': 'Test1'}) def test_single_suite_to_file_no_prettyprint(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1')]), to_file=True, prettyprint=False)[0] verify_test_case(self, tcs[0], {'name': 'Test1'}) def test_multiple_suites_to_file(self): tss = [TestSuite('suite1', [TestCase('Test1')]), TestSuite('suite2', [TestCase('Test2')])] suites = serialize_and_read(tss, to_file=True) self.assertEqual('suite1', suites[0][0].attributes['name'].value) verify_test_case(self, suites[0][1][0], {'name': 'Test1'}) self.assertEqual('suite2', suites[1][0].attributes['name'].value) verify_test_case(self, suites[1][1][0], {'name': 'Test2'}) def test_multiple_suites_to_string(self): tss = [TestSuite('suite1', [TestCase('Test1')]), TestSuite('suite2', [TestCase('Test2')])] suites = serialize_and_read(tss) self.assertEqual('suite1', suites[0][0].attributes['name'].value) verify_test_case(self, suites[0][1][0], {'name': 'Test1'}) self.assertEqual('suite2', suites[1][0].attributes['name'].value) verify_test_case(self, suites[1][1][0], {'name': 'Test2'}) def test_attribute_time(self): tss = [TestSuite('suite1', [TestCase('Test1', 'some.class.name', 123.345), TestCase('Test2', 'some2.class.name', 123.345)]), TestSuite('suite2', [TestCase('Test2')])] suites = serialize_and_read(tss) self.assertEqual('suite1', suites[0][0].attributes['name'].value) self.assertEqual('246.69', suites[0][0].attributes['time'].value) self.assertEqual('suite2', suites[1][0].attributes['name'].value) # here the time in testsuite is "0" even there is no attribute time for # testcase self.assertEqual('0', suites[1][0].attributes['time'].value) # @todo: add more tests for the other attributes and properties def test_to_xml_string(self): test_suites = [TestSuite('suite1', [TestCase('Test1')]), TestSuite('suite2', [TestCase('Test2')])] xml_string = TestSuite.to_xml_string(test_suites) if PY2: self.assertTrue(isinstance(xml_string, unicode)) expected_xml_string = textwrap.dedent(""" \t \t\t \t \t \t\t \t """.strip("\n")) # NOQA self.assertEqual(xml_string, expected_xml_string) def test_to_xml_string_test_suites_not_a_list(self): test_suites = TestSuite('suite1', [TestCase('Test1')]) try: TestSuite.to_xml_string(test_suites) except Exception as exc: self.assertEqual( str(exc), 'test_suites must be a list of test suites') class TestCaseTests(unittest.TestCase): def test_init(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1')]))[0] verify_test_case(self, tcs[0], {'name': 'Test1'}) def test_init_classname(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1', 'some.class.name')]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name'}) def test_init_classname_time(self): (ts, tcs) = serialize_and_read( TestSuite('test', [TestCase('Test1', 'some.class.name', 123.345)]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name', 'time': ("%f" % 123.345)}) def test_init_stderr(self): (ts, tcs) = serialize_and_read( TestSuite( 'test', [TestCase('Test1', 'some.class.name', 123.345, stderr='I am stderr!')]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name', 'time': ("%f" % 123.345)}, stderr='I am stderr!') def test_init_stdout_stderr(self): (ts, tcs) = serialize_and_read( TestSuite( 'test', [TestCase( 'Test1', 'some.class.name', 123.345, 'I am stdout!', 'I am stderr!')]))[0] verify_test_case( self, tcs[0], {'name': 'Test1', 'classname': 'some.class.name', 'time': ("%f" % 123.345)}, stdout='I am stdout!', stderr='I am stderr!') def test_init_failure_message(self): tc = TestCase('Failure-Message') tc.add_failure_info("failure message") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Message'}, failure_message="failure message") def test_init_failure_output(self): tc = TestCase('Failure-Output') tc.add_failure_info(output="I failed!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Output'}, failure_output="I failed!") def test_init_failure(self): tc = TestCase('Failure-Message-and-Output') tc.add_failure_info("failure message", "I failed!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Message-and-Output'}, failure_message="failure message", failure_output="I failed!") def test_init_error_message(self): tc = TestCase('Error-Message') tc.add_error_info("error message") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Error-Message'}, error_message="error message") def test_init_error_output(self): tc = TestCase('Error-Output') tc.add_error_info(output="I errored!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Error-Output'}, error_output="I errored!") def test_init_error(self): tc = TestCase('Error-Message-and-Output') tc.add_error_info("error message", "I errored!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Error-Message-and-Output'}, error_message="error message", error_output="I errored!") def test_init_skipped_message(self): tc = TestCase('Skipped-Message') tc.add_skipped_info("skipped message") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Skipped-Message'}, skipped_message="skipped message") def test_init_skipped_output(self): tc = TestCase('Skipped-Output') tc.add_skipped_info(output="I skipped!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Skipped-Output'}, skipped_output="I skipped!") def test_init_skipped_err_output(self): tc = TestCase('Skipped-Output') tc.add_skipped_info(output="I skipped!") tc.add_error_info(output="I skipped with an error!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Skipped-Output'}, skipped_output="I skipped!", error_output="I skipped with an error!") def test_init_skipped(self): tc = TestCase('Skipped-Message-and-Output') tc.add_skipped_info("skipped message", "I skipped!") (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Skipped-Message-and-Output'}, skipped_message="skipped message", skipped_output="I skipped!") def test_init_legal_unicode_char(self): tc = TestCase('Failure-Message') tc.add_failure_info( u("failure message with legal unicode char: [\x22]")) (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Message'}, failure_message=u( "failure message with legal unicode char: [\x22]")) def test_init_illegal_unicode_char(self): tc = TestCase('Failure-Message') tc.add_failure_info( u("failure message with illegal unicode char: [\x02]")) (ts, tcs) = serialize_and_read(TestSuite('test', [tc]))[0] verify_test_case( self, tcs[0], {'name': 'Failure-Message'}, failure_message=u( "failure message with illegal unicode char: []")) def test_init_utf8(self): tc = TestCase('Test äöü', 'some.class.name.äöü', 123.345, 'I am stdöüt!', 'I am stdärr!') tc.add_skipped_info(message='Skipped äöü', output="I skippäd!") tc.add_error_info(message='Skipped error äöü', output="I skippäd with an error!") test_suite = TestSuite('Test UTF-8', [tc]) (ts, tcs) = serialize_and_read(test_suite, encoding='utf-8')[0] verify_test_case(self, tcs[0], {'name': decode('Test äöü', 'utf-8'), 'classname': decode('some.class.name.äöü', 'utf-8'), 'time': ("%f" % 123.345)}, stdout=decode('I am stdöüt!', 'utf-8'), stderr=decode('I am stdärr!', 'utf-8'), skipped_message=decode('Skipped äöü', 'utf-8'), skipped_output=decode('I skippäd!', 'utf-8'), error_message=decode('Skipped error äöü', 'utf-8'), error_output=decode('I skippäd with an error!', 'utf-8')) def test_init_unicode(self): tc = TestCase(decode('Test äöü', 'utf-8'), decode('some.class.name.äöü', 'utf-8'), 123.345, decode('I am stdöüt!', 'utf-8'), decode('I am stdärr!', 'utf-8')) tc.add_skipped_info(message=decode('Skipped äöü', 'utf-8'), output=decode('I skippäd!', 'utf-8')) tc.add_error_info(message=decode('Skipped error äöü', 'utf-8'), output=decode('I skippäd with an error!', 'utf-8')) (ts, tcs) = serialize_and_read(TestSuite('Test Unicode', [tc]))[0] verify_test_case(self, tcs[0], {'name': decode('Test äöü', 'utf-8'), 'classname': decode('some.class.name.äöü', 'utf-8'), 'time': ("%f" % 123.345)}, stdout=decode('I am stdöüt!', 'utf-8'), stderr=decode('I am stdärr!', 'utf-8'), skipped_message=decode('Skipped äöü', 'utf-8'), skipped_output=decode('I skippäd!', 'utf-8'), error_message=decode('Skipped error äöü', 'utf-8'), error_output=decode('I skippäd with an error!', 'utf-8')) def verify_test_case(tc, test_case_element, expected_attributes, error_message=None, error_output=None, failure_message=None, failure_output=None, skipped_message=None, skipped_output=None, stdout=None, stderr=None): for k, v in expected_attributes.items(): tc.assertEqual(v, test_case_element.attributes[k].value) for k in test_case_element.attributes.keys(): tc.assertTrue(k in expected_attributes.keys()) if stderr: tc.assertEqual( stderr, test_case_element.getElementsByTagName( 'system-err')[0].firstChild.nodeValue.strip()) if stdout: tc.assertEqual( stdout, test_case_element.getElementsByTagName( 'system-out')[0].firstChild.nodeValue.strip()) errors = test_case_element.getElementsByTagName('error') if error_message or error_output: tc.assertTrue(len(errors) > 0) else: tc.assertEqual(0, len(errors)) if error_message: tc.assertEqual( error_message, errors[0].attributes['message'].value) if error_output: tc.assertEqual( error_output, errors[0].firstChild.nodeValue.strip()) failures = test_case_element.getElementsByTagName('failure') if failure_message or failure_output: tc.assertTrue(len(failures) > 0) else: tc.assertEqual(0, len(failures)) if failure_message: tc.assertEqual( failure_message, failures[0].attributes['message'].value) if failure_output: tc.assertEqual( failure_output, failures[0].firstChild.nodeValue.strip()) skipped = test_case_element.getElementsByTagName('skipped') if skipped_message or skipped_output: tc.assertTrue(len(skipped) > 0) else: tc.assertEqual(0, len(skipped)) if __name__ == '__main__': unittest.main() junit-xml-1.6/tox.ini0000644000076500000240000000114512547631326014342 0ustar bbstaff00000000000000[tox] envlist = py26, py27, pypy, py32, py33, py34, cover, flake8 sitepackages = False [testenv] deps = pytest pytest-sugar six commands = py.test \ --junitxml={envlogdir}/junit-{envname}.xml \ {posargs} [testenv:cover] deps = pytest pytest-sugar pytest-cov six commands = py.test \ --cov=junit_xml \ --cov-report=term-missing \ --cov-report=xml \ --cov-report=html \ {posargs} [testenv:flake8] deps = pytest pytest-sugar pytest-flake8 six commands = py.test \ --flake8 \ {posargs}