Skip to content

Commit

Permalink
Renamed the fixture record_xml_property to record_property and adapte…
Browse files Browse the repository at this point in the history
…d logic so that the properties are passed to the TestReport object and thus allow compatibility with pytest-xdist.
  • Loading branch information
carlos-jenkins committed Feb 20, 2018
1 parent 97bb6ab commit dd7120c
Show file tree
Hide file tree
Showing 10 changed files with 108 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(request):
"""(Deprecated) use record_property."""
import warnings
from _pytest import deprecated
warnings.warn(
deprecated.RECORD_XML_PROPERTY,
DeprecationWarning,
stacklevel=2
)

return record_property(request)


@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: 7 additions & 1 deletion _pytest/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +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,
item.user_properties,
sections, duration)


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

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

Expand All @@ -348,6 +350,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.
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_property, record_xml_attribute, recwarn, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1
Expand Down
56 changes: 45 additions & 11 deletions doc/en/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ For more information see :ref:`marks <mark>`.
::

pytest --pyargs pkg.testing
This will import ``pkg.testing`` and use its filesystem location to find and run tests from.


Expand Down 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 dd7120c

Please sign in to comment.