Test assertions¶
-
class
xmlunittest.
XmlTestCase
¶ Base class one can extends to use XML assertion methods. As this class only provide assert* methods, there is nothing more to do.
Simple as it always should be.
This class extends
unittest.TestCase
andXmlTestMixin
. If you want a description of assertion methods, you should read next the description of base classXmlTestMixin
.
-
class
xmlunittest.
XmlTestMixin
¶ Base class that only provide assertion methods. To use, one must extends both
unittest.TestCase
andXmlTestMixin
. Of course, it can use any subclass ofunittest.TestCase
, in combination withXmlTestMixin
without effort.For example:
class TestUsingMixin(unittest.TestCase, xmlunittest.XmlTestMixin): def test_my_test(self): data = my_module.generate_xml() # unittest.TestCase assert self.assertIsNotNone(data) # xmlunittest.XmlTestMixin assert self.assertXmlDocument(data)
Document assertions¶
-
XmlTestMixin.
assertXmlDocument
(data)¶ Parameters: data (string) – XML formated string Return type: lxml.etree._Element Assert data is a valid XML formated string. This method will parse string with lxml.etree.fromstring. If parsing failed (raise an XMLSyntaxError), the test fails.
-
XmlTestMixin.
assertXmlPartial
(partial_data, root_tag=None)¶ Parameters: partial_data (string) – Partial document as XML formated string Return type: lxml.etree._Element Assert partial_data is a partially XML formated string. This method will encapsulate the string into a root element, and then try to parse the string as a normal XML document.
If the parsing failed, test will fail. If the parsing’s result does not have any element child, the test will also fail, because it expects a partial document*, not just a string.
Optional named arguments
Parameters: root_tag (string) – Optional, root element’s tag name One can provide the root element’s tag name to the method for their own convenience.
Example
# ... def test_custom_test(self): data = """ <partial>a</partial> <partial>b</partial> """ root = self.assertXmlPartial(data) # Make some assert on the result's document. self.assertXpathValues(root, './partial/text()', ('a', 'b')) # ...
Element assertions¶
-
XmlTestMixin.
assertXmlNamespace
(node, prefix, uri)¶ Parameters: - node – Element node
- prefix (string) – Expected namespace’s prefix
- uri (string) – Expected namespace’s URI
Asserts node declares namespace uri using prefix.
Example
# ... def test_custom_test(self): data = """<?xml version="1.0" encoding="UTF-8" ?> <root xmlns:ns="uri"/>""" root = self.assertXmlDocument(data) self.assertXmlNamespace(root, 'ns', 'uri') # ...
-
XmlTestMixin.
assertXmlHasAttribute
(node, attribute, **kwargs)¶ Parameters: - node – Element node
- attribute (string) – Expected attribute’s name (using prefix:name notation
Asserts node has the given attribute.
Argument attribute must be the attribute’s name, with namespace’s prefix (notation ‘ns:att’ and not ‘{uri}att’).
Optional named arguments
Parameters: - expected_value (string) – Optional, expected attribute’s value
- expected_values (tuple) – Optional, list of accepted attribute’s value
expected_value and expected_values are mutually exclusive.
Example
# ... def test_custom_test(self): data = """<root a="1" />""" root = self.assertXmlDocument(data) # All these tests will pass self.assertXmlHasAttribute(root, 'a') self.assertXmlHasAttribute(root, 'a', expected_value='1') self.assertXmlHasAttribute(root, 'a', expected_values=('1', '2')) # ...
-
XmlTestMixin.
assertXmlNode
(node, **kwargs)¶ Asserts node is an element node, and can assert expected tag and value.
Optional named arguments
Parameters: - tag (string) – Expected node’s tag name
- text (string) – Expected node’s text value
- text_in (tuple) – Accepted node’s text values
text and text_in are mutually exclusive.
Example
# ... def test_custom_test(self): data = """<root>some_value</root>""" root = self.assertXmlDocument(data) # All these tests will pass self.assertXmlNode(root) self.assertXmlNode(root, tag='root') self.assertXmlNode(root, tag='root', text='some_value') self.assertXmlNode(root, tag='root', text_in=('some_value', 'other')) # ...
XPath expression assertions¶
-
XmlTestMixin.
assertXpathsExist
(node, xpaths, default_ns_prefix='ns')¶ Parameters: - node – Element node
- xpaths (tuple) – List of XPath expressions
- default_ns_prefix (string) – Optional, value of the default namespace prefix
Asserts each XPath from xpaths evaluates on node to at least one element or a not None value.
Example
# ... def test_custom_test(self): data = """<root rootAtt="value"> <child>value</child> <child att="1"/> <child att="2"/> </root>""" root = self.assertXmlDocument(data) # All these XPath expression returns a not `None` value. self.assertXpathsExist(root, ('@rootAtt', './child', './child[@att="1"]')) # ...
-
XmlTestMixin.
assertXpathsOnlyOne
(node, xpaths, default_ns_prefix='ns')¶ Parameters: - node – Element node
- xpaths (tuple) – List of XPath expressions
- default_ns_prefix (string) – Optional, value of the default namespace prefix
Asserts each XPath’s result returns only one element.
Example
# ... def test_custom_test(self): data = """<root> <child att="1"/> <child att="2"/> <unique>this element is unique</unique> </root>""" root = self.assertXmlDocument(data) # All these XPath expression returns only one result self.assertXpathsOnlyOne(root, ('./unique', './child[@att="1"]')) # ...
-
XmlTestMixin.
assertXpathsUniqueValue
(node, xpaths, default_ns_prefix='ns')¶ Parameters: - node – Element node
- xpaths (tuple) – List of XPath expressions
- default_ns_prefix (string) – Optional, value of the default namespace prefix
Asserts each XPath’s result’s value is unique in the selected elements.
One can use this method to check node’s value, and node’s attribute’s value, in a set of nodes selected by XPath expression.
Example
# ... def test_custom_test(self): data = """<?xml version="1.0" encoding="UTF-8" ?> <root> <sub subAtt="unique" id="1">unique 1</sub> <sub subAtt="notUnique" id="2">unique 2</sub> <sub subAtt="notUnique" id="3">unique 3</sub> <multiple>twice</multiple> <multiple>twice</multiple> </root>""" root = self.assertXmlDocument(data) # This will pass self.assertXpathsUniqueValue(root, ('./sub/@id', './sub/text()')) # These won't pass self.assertXpathsUniqueValue(root, ('./sub/@subAtt',)) self.assertXpathsUniqueValue(root, ('./multiple/text()',)) # ...
-
XmlTestMixin.
assertXpathValues
(node, xpath, values, default_ns_prefix='ns')¶ Parameters: - node – Element node
- xpath (string) – XPath expression to select elements
- values (tuple) – List of accepted values
- default_ns_prefix (string) – Optional, value of the default namespace prefix
Asserts each selected element’s result from XPath expression is in the list of expected values.
Example
# ... def test_custom_test(self): data = """<?xml version="1.0" encoding="UTF-8" ?> <root> <sub id="1">a</sub> <sub id="2">a</sub> <sub id="3">b</sub> <sub id="4">c</sub> </root>""" root = self.assertXmlDocument(data) # Select attribute's value self.assertXpathValues(root, './sub/@id', ('1', '2', '3', '4')) # Select node's text value self.assertXpathValues(root, './sub/text()', ('a', 'b', 'c')) # ...
XML schema conformance assertion¶
The following methods let you check the conformance of an XML document or node according to a schema. Any validation schema language that is supported by lxml may be used:
- DTD
- XSchema
- RelaxNG
- Schematron
Please read Validation with lxml to build your own schema objects in these various schema languages.
-
XmlTestMixin.
assertXmlValidDTD
(node, dtd=None, filename=None)¶ Parameters: node ( lxml.etree.Element
) – Node element to valid using a DTDAsserts that the given node element can be validated successfuly by the given DTD.
The DTD can be provided as a simple string, or as a previously parsed DTD using
lxml.etree.DTD
. It can be also provided by a filename.Optional arguments
One can provide either a DTD as a string, or a DTD element from LXML, or the filename of the DTD.
Parameters: - dtd (string |
lxml.etree.DTD
) – DTD used to valid the given node element. Can be a string or an LXML DTD element - filename (string) – Path to the expected DTD for validation.
dtd and filename are mutualy exclusive.
Example using a filename
def my_custom_test(self): """Check XML generated using DTD at path/to/file.dtd. The content of the DTD file is: <!ELEMENT root (child)> <!ELEMENT child EMPTY> <!ATTLIST child id ID #REQUIRED> """ dtd_filename = 'path/to/file.dtd' data = b"""<?xml version="1.0" encoding="utf-8"?> <root> <child id="child1"/> </root> """ root = test_case.assertXmlDocument(data) self.assertXmlValidDTD(root, filename=dtd_filename)
- dtd (string |
-
XmlTestMixin.
assertXmlValidXSchema
(node, xschema=None, filename=None)¶ Parameters: node ( lxml.etree.Element
) – Node element to valid using an XML SchemaAsserts that the given node element can be validated successfuly by the given XML Schema.
The XML Schema can be provided as a simple string, or as a previously parsed XSchema using
lxml.etree.XMLSChema
. It can be also provided by a filename.Optional arguments
One can provide either an XMLSchema as a string, or an XMLSchema element from LXML, or the filename of the XMLSchema.
Parameters: - xschema (string |
lxml.etree.XMLSchema
) – XMLSchema used to valid the given node element. Can be a string or an LXML XMLSchema element - filename (string) – Path to the expected XMLSchema for validation.
xschema and filename are mutualy exclusive.
Example using a filename
def my_custom_test(self): """Check XML generated using XMLSchema at path/to/xschema.xml. The content of the XMLSchema file is: <?xml version="1.0" encoding="utf-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="root"> <xsd:complexType> <xsd:sequence> <xsd:element name="child" minOccurs="1" maxOccurs="1"> <xsd:complexType> <xsd:simpleContent> <xsd:extension base="xsd:string"> <xsd:attribute name="id" type="xsd:string" use="required" /> </xsd:extension> </xsd:simpleContent> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> """ xschema_filename = 'path/to/xschema.xml' data = b"""<?xml version="1.0" encoding="utf-8"?> <root> <child id="child1"/> </root> """ root = test_case.assertXmlDocument(data) self.assertXmlValidXSchema(root, filename=xschema_filename)
- xschema (string |
-
XmlTestMixin.
assertXmlValidRelaxNG
(node, relaxng=None, filename=None)¶ Parameters: node ( lxml.etree.Element
) – Node element to valid using a RelaxNGAsserts that the given node element can be validated successfuly by the given RelaxNG.
The RelaxNG can be provided as a simple string, or as a previously parsed RelaxNG using
lxml.etree.RelaxNG
. It can be also provided by a filename.Optional arguments
One can provide either a RelaxNG as a string, or a RelaxNG element from LXML, or the filename of the RelaxNG.
Parameters: - relaxng (string |
lxml.etree.RelaxNG
) – RelaxNG used to valid the given node element. Can be a string or an LXML RelaxNG element - filename (string) – Path to the expected RelaxNG for validation.
relaxng and filename are mutualy exclusive.
Example using a filename
def my_custom_test(self): """Check XML generated using RelaxNG at path/to/relaxng.xml. The content of the RelaxNG file is: <?xml version="1.0" encoding="utf-8"?> <rng:element name="root" xmlns:rng="http://relaxng.org/ns/structure/1.0"> <rng:element name="child"> <rng:attribute name="id"> <rng:text /> </rng:attribute> </rng:element> </rng:element> """ relaxng_filename = 'path/to/relaxng.xml' data = b"""<?xml version="1.0" encoding="utf-8"?> <root> <child id="child1"/> </root> """ root = test_case.assertXmlDocument(data) self.assertXmlValidRelaxNG(root, filename=relaxng_filename)
- relaxng (string |
XML documents comparison assertion¶
Sometimes, one may want to check a global XML document, because they know
exactly what is expected, and can rely on a kind of “string compare”. Of
course, XML is not a simple string, and requires more than just an
assert data == expected
, because order of elements can vary, order of
attributes too, namespaces can come into play, etc.
In these cases, one can use the powerful - also dangerous - feature of LXML Output Checker. See also the documentation of the module doctestcompare for more information on the underlying implementation.
And as always, remember that the whole purpose of this xmlunittest
is to avoid any comparison of XML formated strings. But, whatever, this
function could help. Maybe.
-
XmlTestMixin.
assertXmlEquivalentOutputs
(data, expected)¶ Parameters: - data (string) – XML formated string to check
- expected (string) – XML formated string used as reference
Asserts both XML formated string are equivalent. The comparison ignores spaces within nodes and namespaces may be associated to diffrerent prefixes, thus requiring only the same URL.
If a difference is found, an
AssertionError
is raised, with the comparison failure’s message as error’s message.Note
The name
assertXmlEquivalentOutputs
is cleary a way to prevent user to missunderstand the meaning of this assertion: it checks only similar outputs, not document.Note
This method only accept
string
as arguments. This is an opinionated implementation choice, as the purpose of this method is to check the result outputs of an XML document.Example
# ... def test_custom_test(self): """Same XML (with different spacings placements and attrs order)""" # This XML string should come from the code one want to test data = b"""<?xml version="1.0" encoding="UTF-8" ?> <root><tag bar="foo" foo="bar"> foo </tag></root>""" # This is the former XML document one can expect, with pretty print expected = b"""<?xml version="1.0" encoding="UTF-8" ?> <root> <tag foo="bar" bar="foo">foo</tag> </root>""" # This will pass test_case.assertXmlEquivalentOutputs(data, expected) # This is another example of result, with a missing attribute data = b"""<?xml version="1.0" encoding="UTF-8" ?> <root> <tag foo="bar"> foo </tag> </root> """ # This won't pass test_case.assertXmlEquivalentOutputs(data, expected)