XML Unittest
xmlunittest is a Python library that extends the built-in `unittest` framework to provide robust assertion methods for testing XML documents. Leveraging `lxml` and XPath, it allows users to validate XML structure, content, and schema conformance, avoiding the pitfalls of direct XML string comparisons. The current version is 1.0.1, with releases typically focusing on compatibility updates and feature enhancements for XML processing.
Warnings
- breaking Prior to version 0.4.0, `xmlunittest` did not explicitly handle namespaces in XPath expressions. If your tests relied on XPath against namespaced XML, you might need to adjust your XPath expressions to properly declare and use namespaces (e.g., `{ns:uri}localname` or by passing a `namespaces` dictionary to assertion methods) after upgrading, or ensure your XML matches a non-namespaced structure if that was the prior implicit assumption.
- gotcha The `xmlunittest` library depends on `lxml`, which can sometimes be challenging to install due to underlying system library requirements (e.g., `libxml2`, `libxslt`). Users might encounter compilation errors if these development headers are not present on their system.
- breaking Versions of `xmlunittest` prior to 1.0.0 (specifically up to 0.3.2) supported Python 2.7. The current version (1.0.1) requires Python >= 3.8. Migrating from older versions on Python 2.x to the latest will require a Python 3 environment.
- gotcha A common mistake when testing XML is to perform direct string comparisons. `xmlunittest` explicitly aims to solve the issues arising from such comparisons (e.g., attribute order, whitespace, optional elements). Users should leverage `XmlTestCase`'s specialized assertion methods for robust XML validation, rather than `assertEqual(xml_string_1, xml_string_2)`.
Install
-
pip install xmlunittest
Imports
- XmlTestCase
from xmlunittest import XmlTestCase
Quickstart
import unittest
from xmlunittest import XmlTestCase
class MyXmlTests(XmlTestCase):
def test_basic_xml_content(self):
data = """<root><item id='1'>Value A</item><item id='2'>Value B</item></root>"""
self.assertXmlDocument(data)
self.assertXpathsExist(data, ['/root', '/root/item', '/root/item[@id="1"]'])
self.assertXpathsOnlyOne(data, ['/root/item[@id="1"]'])
self.assertXpathValues(data, '//item[@id="1"]', ['Value A'])
self.assertXpathAttributes(data, '//item[@id="1"]', {'id': '1'})
def test_with_namespaces(self):
data = """<root xmlns:ns='http://example.com/ns'><ns:element>Hello</ns:element></root>"""
# Pass namespaces explicitly when using XPath with namespaces
self.assertXpathValues(data, '//ns:element', ['Hello'], namespaces={'ns': 'http://example.com/ns'})
if __name__ == '__main__':
unittest.main()