diff --git a/changelog/5202.trivial.rst b/changelog/5202.trivial.rst new file mode 100644 index 000000000..2eaaf0ca4 --- /dev/null +++ b/changelog/5202.trivial.rst @@ -0,0 +1,4 @@ +``record_property`` now emits a ``PytestWarning`` when used with ``junit_family=xunit2``: the fixture generates +``property`` tags as children of ``testcase``, which is not permitted according to the most +`recent schema `__. diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 3a5f31735..f1b7763e2 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -281,6 +281,21 @@ class _NodeReporter(object): self.to_xml = lambda: py.xml.raw(data) +def _warn_incompatibility_with_xunit2(request, fixture_name): + """Emits a PytestWarning about the given fixture being incompatible with newer xunit revisions""" + from _pytest.warning_types import PytestWarning + + xml = getattr(request.config, "_xml", None) + if xml is not None and xml.family not in ("xunit1", "legacy"): + request.node.warn( + PytestWarning( + "{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1')".format( + fixture_name=fixture_name, family=xml.family + ) + ) + ) + + @pytest.fixture def record_property(request): """Add an extra properties the calling test. @@ -294,6 +309,7 @@ def record_property(request): def test_function(record_property): record_property("example_key", 1) """ + _warn_incompatibility_with_xunit2(request, "record_property") def append_property(name, value): request.node.user_properties.append((name, value)) @@ -307,27 +323,22 @@ def record_xml_attribute(request): The fixture is callable with ``(name, value)``, with value being automatically xml-encoded """ - from _pytest.warning_types import PytestExperimentalApiWarning, PytestWarning + from _pytest.warning_types import PytestExperimentalApiWarning request.node.warn( PytestExperimentalApiWarning("record_xml_attribute is an experimental feature") ) + _warn_incompatibility_with_xunit2(request, "record_xml_attribute") + # Declare noop def add_attr_noop(name, value): pass attr_func = add_attr_noop - xml = getattr(request.config, "_xml", None) - if xml is not None and xml.family != "xunit1": - request.node.warn( - PytestWarning( - "record_xml_attribute is incompatible with junit_family: " - "%s (use: legacy|xunit1)" % xml.family - ) - ) - elif xml is not None: + xml = getattr(request.config, "_xml", None) + if xml is not None: node_reporter = xml.node_reporter(request.node.nodeid) attr_func = node_reporter.add_attribute diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index 82e984785..a32eab2ec 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -993,6 +993,20 @@ def test_record_property_same_name(testdir): pnodes[1].assert_attr(name="foo", value="baz") +@pytest.mark.parametrize("fixture_name", ["record_property", "record_xml_attribute"]) +def test_record_fixtures_without_junitxml(testdir, fixture_name): + testdir.makepyfile( + """ + def test_record({fixture_name}): + {fixture_name}("foo", "bar") + """.format( + fixture_name=fixture_name + ) + ) + result = testdir.runpytest() + assert result.ret == 0 + + @pytest.mark.filterwarnings("default") def test_record_attribute(testdir): testdir.makeini( @@ -1023,8 +1037,9 @@ def test_record_attribute(testdir): @pytest.mark.filterwarnings("default") -def test_record_attribute_xunit2(testdir): - """Ensure record_xml_attribute drops values when outside of legacy family +@pytest.mark.parametrize("fixture_name", ["record_xml_attribute", "record_property"]) +def test_record_fixtures_xunit2(testdir, fixture_name): + """Ensure record_xml_attribute and record_property drop values when outside of legacy family """ testdir.makeini( """ @@ -1037,21 +1052,28 @@ def test_record_attribute_xunit2(testdir): import pytest @pytest.fixture - def other(record_xml_attribute): - record_xml_attribute("bar", 1) - def test_record(record_xml_attribute, other): - record_xml_attribute("foo", "<1"); - """ + def other({fixture_name}): + {fixture_name}("bar", 1) + def test_record({fixture_name}, other): + {fixture_name}("foo", "<1"); + """.format( + fixture_name=fixture_name + ) ) result, dom = runandparse(testdir, "-rw") - result.stdout.fnmatch_lines( - [ - "*test_record_attribute_xunit2.py:6:*record_xml_attribute is an experimental feature", - "*test_record_attribute_xunit2.py:6:*record_xml_attribute is incompatible with " - "junit_family: xunit2 (use: legacy|xunit1)", - ] - ) + expected_lines = [] + if fixture_name == "record_xml_attribute": + expected_lines.append( + "*test_record_fixtures_xunit2.py:6:*record_xml_attribute is an experimental feature" + ) + expected_lines = [ + "*test_record_fixtures_xunit2.py:6:*{fixture_name} is incompatible " + "with junit_family 'xunit2' (use 'legacy' or 'xunit1')".format( + fixture_name=fixture_name + ) + ] + result.stdout.fnmatch_lines(expected_lines) def test_random_report_log_xdist(testdir, monkeypatch):