Skip to content

Commit

Permalink
Merge pull request #2770 from HPENetworking/master
Browse files Browse the repository at this point in the history
Make record_xml_property generic and compatible with xdist and markers.
  • Loading branch information
RonnyPfannschmidt authored Feb 22, 2018
2 parents 7336dbb + 567b1ea commit 54e63b7
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 40 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Brianna Laugher
Bruno Oliveira
Cal Leeming
Carl Friedrich Bolz
Carlos Jenkins
Ceridwen
Charles Cloud
Charnjit SiNGH (CCSJ)
Expand Down
6 changes: 6 additions & 0 deletions _pytest/deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class RemovedInPytest4Warning(DeprecationWarning):
"For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
)

RECORD_XML_PROPERTY = (
'Fixture renamed from "record_xml_property" to "record_property" as user '
'properties are now available to all reporters.\n'
'"record_xml_property" is now deprecated.'
)

COLLECTOR_MAKEITEM = RemovedInPytest4Warning(
"pycollector makeitem was removed "
"as it is an accidentially leaked internal api"
Expand Down
44 changes: 29 additions & 15 deletions _pytest/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,31 +233,41 @@ def finalize(self):


@pytest.fixture
def record_xml_property(request):
"""Add extra xml properties to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being automatically
xml-encoded.
def record_property(request):
"""Add an extra properties the calling test.
User properties become part of the test report and are available to the
configured reporters, like JUnit XML.
The fixture is callable with ``(name, value)``.
"""
request.node.warn(
code='C3',
message='record_xml_property is an experimental feature',
message='record_property is an experimental feature',
)
xml = getattr(request.config, "_xml", None)
if xml is not None:
node_reporter = xml.node_reporter(request.node.nodeid)
return node_reporter.add_property
else:
def add_property_noop(name, value):
pass

return add_property_noop
def append_property(name, value):
request.node.user_properties.append((name, value))
return append_property


@pytest.fixture
def record_xml_property(record_property):
"""(Deprecated) use record_property."""
import warnings
from _pytest import deprecated
warnings.warn(
deprecated.RECORD_XML_PROPERTY,
DeprecationWarning,
stacklevel=2
)

return record_property


@pytest.fixture
def record_xml_attribute(request):
"""Add extra xml attributes to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being automatically
xml-encoded
The fixture is callable with ``(name, value)``, with value being
automatically xml-encoded
"""
request.node.warn(
code='C3',
Expand Down Expand Up @@ -442,6 +452,10 @@ def pytest_runtest_logreport(self, report):
if report.when == "teardown":
reporter = self._opentestcase(report)
reporter.write_captured_output(report)

for propname, propvalue in report.user_properties:
reporter.add_property(propname, propvalue)

self.finalize(report)
report_wid = getattr(report, "worker_id", None)
report_ii = getattr(report, "item_index", None)
Expand Down
4 changes: 4 additions & 0 deletions _pytest/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,10 @@ def __init__(self, name, parent=None, config=None, session=None):
super(Item, self).__init__(name, parent, config, session)
self._report_sections = []

#: user properties is a list of tuples (name, value) that holds user
#: defined properties for this test.
self.user_properties = []

def add_report_section(self, when, key, content):
"""
Adds a new report section, similar to what's done internally to add stdout and
Expand Down
8 changes: 6 additions & 2 deletions _pytest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def pytest_runtest_makereport(item, call):
sections.append(("Captured %s %s" % (key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
sections, duration)
sections, duration, user_properties=item.user_properties)


class TestReport(BaseReport):
Expand All @@ -326,7 +326,7 @@ class TestReport(BaseReport):
"""

def __init__(self, nodeid, location, keywords, outcome,
longrepr, when, sections=(), duration=0, **extra):
longrepr, when, sections=(), duration=0, user_properties=(), **extra):
#: normalized collection node id
self.nodeid = nodeid

Expand All @@ -348,6 +348,10 @@ def __init__(self, nodeid, location, keywords, outcome,
#: one of 'setup', 'call', 'teardown' to indicate runtest phase.
self.when = when

#: user properties is a list of tuples (name, value) that holds user
#: defined properties of the test
self.user_properties = user_properties

#: list of pairs ``(str, str)`` of extra information which needs to
#: marshallable. Used by pytest to add captured text
#: from ``stdout`` and ``stderr``, but may be used by other plugins
Expand Down
2 changes: 2 additions & 0 deletions changelog/2770.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``record_xml_property`` renamed to ``record_property`` and is now compatible with xdist, markers and any reporter.
``record_xml_property`` name is now deprecated.
1 change: 1 addition & 0 deletions changelog/2770.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``.
9 changes: 5 additions & 4 deletions doc/en/builtin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ You can ask for available builtin or project-custom
Inject names into the doctest namespace.
pytestconfig
the pytest config object with access to command line opts.
record_xml_property
Add extra xml properties to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being automatically
xml-encoded.
record_property
Add an extra properties the calling test.
User properties become part of the test report and are available to the
configured reporters, like JUnit XML.
The fixture is callable with ``(name, value)``.
record_xml_attribute
Add extra xml attributes to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being automatically
Expand Down
2 changes: 1 addition & 1 deletion doc/en/example/simple.rst
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ We can run this::
file $REGENDOC_TMPDIR/b/test_error.py, line 1
def test_root(db): # no db here, will error out
E fixture 'db' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_xml_attribute, record_property, recwarn, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1
Expand Down
54 changes: 44 additions & 10 deletions doc/en/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,19 +220,24 @@ To set the name of the root test suite xml item, you can configure the ``junit_s
[pytest]
junit_suite_name = my_suite
record_xml_property
record_property
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. versionadded:: 2.8
.. versionchanged:: 3.5

Fixture renamed from ``record_xml_property`` to ``record_property`` as user
properties are now available to all reporters.
``record_xml_property`` is now deprecated.

If you want to log additional information for a test, you can use the
``record_xml_property`` fixture:
``record_property`` fixture:

.. code-block:: python
def test_function(record_xml_property):
record_xml_property("example_key", 1)
assert 0
def test_function(record_property):
record_property("example_key", 1)
assert True
This will add an extra property ``example_key="1"`` to the generated
``testcase`` tag:
Expand All @@ -245,13 +250,42 @@ This will add an extra property ``example_key="1"`` to the generated
</properties>
</testcase>
.. warning::
Alternatively, you can integrate this functionality with custom markers:

``record_xml_property`` is an experimental feature, and its interface might be replaced
by something more powerful and general in future versions. The
functionality per-se will be kept, however.
.. code-block:: python
# content of conftest.py
def pytest_collection_modifyitems(session, config, items):
for item in items:
marker = item.get_marker('test_id')
if marker is not None:
test_id = marker.args[0]
item.user_properties.append(('test_id', test_id))
And in your tests:

.. code-block:: python
# content of test_function.py
@pytest.mark.test_id(1501)
def test_function():
assert True
Will result in:

.. code-block:: xml
<testcase classname="test_function" file="test_function.py" line="0" name="test_function" time="0.0009">
<properties>
<property name="test_id" value="1501" />
</properties>
</testcase>
.. warning::

Currently it does not work when used with the ``pytest-xdist`` plugin.
``record_property`` is an experimental feature and may change in the future.

Also please note that using this feature will break any schema verification.
This might be a problem when used with some CI servers.
Expand Down
16 changes: 8 additions & 8 deletions testing/test_junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,10 +863,10 @@ def test_record_property(testdir):
import pytest
@pytest.fixture
def other(record_xml_property):
record_xml_property("bar", 1)
def test_record(record_xml_property, other):
record_xml_property("foo", "<1");
def other(record_property):
record_property("bar", 1)
def test_record(record_property, other):
record_property("foo", "<1");
""")
result, dom = runandparse(testdir, '-rw')
node = dom.find_first_by_tag("testsuite")
Expand All @@ -877,15 +877,15 @@ def test_record(record_xml_property, other):
pnodes[1].assert_attr(name="foo", value="<1")
result.stdout.fnmatch_lines([
'test_record_property.py::test_record',
'*record_xml_property*experimental*',
'*record_property*experimental*',
])


def test_record_property_same_name(testdir):
testdir.makepyfile("""
def test_record_with_same_name(record_xml_property):
record_xml_property("foo", "bar")
record_xml_property("foo", "baz")
def test_record_with_same_name(record_property):
record_property("foo", "bar")
record_property("foo", "baz")
""")
result, dom = runandparse(testdir, '-rw')
node = dom.find_first_by_tag("testsuite")
Expand Down

0 comments on commit 54e63b7

Please sign in to comment.