Manipulates JUnit/xUnit Result XML files
Project description
What does it do?
junitparser is a JUnit/xUnit Result XML Parser. Use it to parse and manipulate existing Result XML files, or create new JUnit/xUnit result XMLs from scratch.
There are already a lot of modules that converts JUnit/xUnit XML from a specific format, but you may run into some proprietory or less-known formats and you want to convert them and feed the result to another tool, or, you may want to manipulate the results in your own way. This is where junitparser come into handy.
Why junitparser?
Functionality. There are various JUnit/xUnit XML libraries, some does parsing, some does XML generation, some does manipulation. This module does all in a single package.
Extensibility. JUnit/xUnit is hardly a standardized format. The base format is somewhat universally agreed with, but beyond that, there could be “custom” elements and attributes. junitparser aims to support them all, by allowing the user to monkeypatch and subclass some base classes.
Pythonic. You can manipulate test cases and suites in a pythonic way.
Installation
pip install junitparser
Usage
You should be relatively familiar with the Junit XML format. If not, run pydoc on the exposed classes and functions to see how it’s structured.
Create Junit XML format reports from scratch
You have some test result data, and you want to convert them into junit.xml format.
from junitparser import TestCase, TestSuite, JUnitXml, Skipped, Error
# Create cases
case1 = TestCase('case1')
case1.result = Skipped()
case2 = TestCase('case2')
case2.result = Error('Example error message', 'the_error_type')
# Create suite and add cases
suite = TestSuite('suite1')
suite.add_property('build', '55')
suite.add_testcase(case1)
suite.add_testcase(case2)
suite.remove_testcase(case2)
# Add suite to JunitXml
xml = JUnitXml()
xml.add_testsuite(suite)
xml.write('junit.xml')
Read and manipulate exiting JUnit/xUnit XML files
You have some existing junit.xml files, and you want to modify the content.
from junitparser import JUnitXml
xml = JUnitXml.fromfile('/path/to/junit.xml')
for suite in xml:
# handle suites
for case in suite:
# handle cases
xml.write() # Writes back to file
It is also possible to use a custom parser. For example lxml provides a plethora of parsing options. We can use them this way:
from lxml.etree import XMLParser, parse
from junitparser import JUnitXml
def parse_func(file_path):
xml_parser = XMLParser(huge_tree=True)
return parse(file_path, xml_parser)
xml = JUnitXml.fromfile('/path/to/junit.xml', parse_func)
# process xml...
Merge XML files
You have two or more XML files, and you want to merge them into one.
from junitparser import JUnitXml
xml1 = JUnitXml.fromfile('/path/to/junit1.xml')
xml2 = JUnitXml.fromfile('/path/to/junit2.xml')
newxml = xml1 + xml2
# Alternatively, merge in place
xml1 += xml2
Note that it won’t check for duplicate entries. You need to deal with them on your own.
Create XML with custom attributes
You want to use an attribute that is not supported by default.
from junitparser import TestCase, Attr, IntAttr, FloatAttr
# Add the custom attribute
TestCase.id = IntAttr('id')
TestCase.rate = FloatAttr('rate')
TestCase.custom = Attr('custom')
case = TestCase()
case.id = 123
case.rate = 0.95
case.custom = 'foobar'
Handling XML with custom element
There may be once in 1000 years you want to it this way, but anyways. Suppose you want to add element CustomElement to TestCase.
from junitparser import Element, Attr, TestSuite
# Create the new element by subclassing Element,
# and add custom attributes to it.
class CustomElement(Element):
_tag = 'custom'
foo = Attr()
bar = Attr()
testcase = TestCase()
custom = CustomElement()
testcase.append(custom)
# To find a single sub-element:
testcase.child(CustomElement)
# To iterate over custom elements:
for custom in testcase.iterchildren(CustomElement):
... # Do things with custom element
Handling custom XML attributes
Say you have some data stored in the XML as custom attributes and you want to read them out:
from junitparser import Element, Attr, TestSuite
# Create the new element by subclassing Element or one of its child class,
# and add custom attributes to it.
class MyTestCase(TestCase):
foo = Attr()
xml = JUnitXml.fromfile('/path/to/junit.xml')
for suite in xml:
# handle suites
for case in suite:
my_case = MyTestCase.fromelem(case)
print(my_case.foo)
Command Line
$ junitparser --help
usage: junitparser [-h] [-v] {merge} ...
Junitparser CLI helper.
positional arguments:
{merge} command
merge Merge Junit XML format reports with junitparser.
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
$ junitparser merge --help
usage: junitparser merge [-h] [--glob] paths [paths ...] output
positional arguments:
paths Original XML path(s).
output Merged XML Path.
optional arguments:
-h, --help show this help message and exit
--glob Treat original XML path(s) as glob(s).
Test
You can run the cases directly:
python test.py
Or use pytest:
pytest test.py
Notes
There are some other packages providing similar functionalities. They are out there for a longer time, but might not be as feature-rich or fun as junitparser:
xunitparser: Read JUnit/XUnit XML files and map them to Python objects
xunitgen: Generate xUnit.xml files
xunitmerge: Utility for merging multiple XUnit xml reports into a single xml report.
junit-xml: Creates JUnit XML test result documents that can be read by tools such as Jenkins
Contribute
Please do!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for junitparser-1.6.1-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 62dbc0339e0a0570222e29f58dcb079ec33e18c484d3ac1e0ad6c2b28b81e872 |
|
MD5 | bfb89c86e7aacb3862c10b6ea5475d9e |
|
BLAKE2b-256 | 29abe06439090e1eddc3e48ee460bc2242d4a1601d389e7024996b18565d1656 |