From b47f155d746d3721d03ec5d0280106608849c478 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 12 Jun 2016 00:17:50 +0100 Subject: [PATCH 1/5] Implement tests for --fixtures-per-test --- testing/python/show_fixtures_per_test.py | 137 +++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 testing/python/show_fixtures_per_test.py diff --git a/testing/python/show_fixtures_per_test.py b/testing/python/show_fixtures_per_test.py new file mode 100644 index 000000000..3a34a513d --- /dev/null +++ b/testing/python/show_fixtures_per_test.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + + +def test_no_items_should_not_show_output(testdir): + result = testdir.runpytest('--fixtures-per-test') + assert 'fixtures used by' not in result.stdout.str() + assert result.ret == 0 + + +def test_fixtures_in_module(testdir): + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def _arg0(): + """hidden arg0 fixture""" + @pytest.fixture + def arg1(): + """arg1 docstring""" + def test_arg1(arg1): + pass + ''') + + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_arg1*', + '*from test_fixtures_in_module.py:9*', + 'arg1', + ' arg1 docstring', + ]) + assert "_arg0" not in result.stdout.str() + + +def test_fixtures_in_conftest(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 docstring""" + @pytest.fixture + def arg2(): + """arg2 docstring""" + @pytest.fixture + def arg3(arg1, arg2): + """arg3 + docstring + """ + ''') + p = testdir.makepyfile(''' + def test_arg2(arg2): + pass + def test_arg3(arg3): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_arg2*', + '*from test_fixtures_in_conftest.py:2*', + 'arg2', + ' arg2 docstring', + '*fixtures used by test_arg3*', + '*from test_fixtures_in_conftest.py:4*', + 'arg1', + ' arg1 docstring', + 'arg2', + ' arg2 docstring', + 'arg3', + ' arg3', + ' docstring', + ]) + + +def test_should_show_fixtures_used_by_test(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 from conftest""" + @pytest.fixture + def arg2(): + """arg2 from conftest""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg1(): + """arg1 from testmodule""" + def test_args(arg1, arg2): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_args*', + '*from test_should_show_fixtures_used_by_test.py:6*', + 'arg1', + ' arg1 from testmodule', + 'arg2', + ' arg2 from conftest', + ]) + + +def test_verbose_include_private_fixtures_and_loc(testdir): + testdir.makeconftest(''' + import pytest + @pytest.fixture + def _arg1(): + """_arg1 from conftest""" + @pytest.fixture + def arg2(_arg1): + """arg2 from conftest""" + ''') + p = testdir.makepyfile(''' + import pytest + @pytest.fixture + def arg3(): + """arg3 from testmodule""" + def test_args(arg2, arg3): + pass + ''') + result = testdir.runpytest("--fixtures-per-test", "-v", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*fixtures used by test_args*', + '*from test_verbose_include_private_fixtures_and_loc.py:6*', + '_arg1 -- conftest.py:3', + ' _arg1 from conftest', + 'arg2 -- conftest.py:6', + ' arg2 from conftest', + 'arg3 -- test_verbose_include_private_fixtures_and_loc.py:3', + ' arg3 from testmodule', + ]) From 7eea168106a70b49f9cb7e3d13227eff0cba9e5b Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 12 Jun 2016 00:20:06 +0100 Subject: [PATCH 2/5] Implement show_fixtures_per_test and add cli flag --- _pytest/python.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/_pytest/python.py b/_pytest/python.py index 8eb0d9c73..a9243b36a 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -209,6 +209,13 @@ def pytest_addoption(parser): group.addoption('--fixtures', '--funcargs', action="store_true", dest="showfixtures", default=False, help="show available fixtures, sorted by plugin appearance") + group.addoption( + '--fixtures-per-test', + action="store_true", + dest="show_fixtures_per_test", + default=False, + help="show fixtures per test", + ) parser.addini("usefixtures", type="args", default=[], help="list of default fixtures to be used with this project") parser.addini("python_files", type="args", @@ -230,6 +237,9 @@ def pytest_cmdline_main(config): if config.option.showfixtures: showfixtures(config) return 0 + if config.option.show_fixtures_per_test: + show_fixtures_per_test(config) + return 0 def pytest_generate_tests(metafunc): @@ -1195,6 +1205,67 @@ def idmaker(argnames, argvalues, idfn=None, ids=None, config=None): counters[testid] += 1 return ids + +def show_fixtures_per_test(config): + from _pytest.main import wrap_session + return wrap_session(config, _show_fixtures_per_test) + + +def _show_fixtures_per_test(config, session): + import _pytest.config + session.perform_collect() + curdir = py.path.local() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + def get_best_rel(func): + loc = getlocation(func, curdir) + return curdir.bestrelpath(loc) + + def write_fixture(fixture_def): + argname = fixture_def.argname + + if verbose <= 0 and argname.startswith("_"): + return + if verbose > 0: + bestrel = get_best_rel(fixture_def.func) + funcargspec = "{} -- {}".format(argname, bestrel) + else: + funcargspec = argname + tw.line(funcargspec, green=True) + + INDENT = ' {}' + fixture_doc = fixture_def.func.__doc__ + + if fixture_doc: + for line in fixture_doc.strip().split('\n'): + tw.line(INDENT.format(line.strip())) + else: + tw.line(INDENT.format('no docstring available'), red=True) + + def write_item(item): + name2fixturedefs = item._fixtureinfo.name2fixturedefs + + if not name2fixturedefs: + # The given test item does not use any fixtures + return + bestrel = get_best_rel(item.function) + + tw.line() + tw.sep('-', 'fixtures used by {}'.format(item.name)) + tw.sep('-', 'from {}'.format(bestrel)) + for argname, fixture_defs in sorted(name2fixturedefs.items()): + assert fixture_defs is not None + if not fixture_defs: + continue + # The last fixture def item in the list is expected + # to be the one used by the test item + write_fixture(fixture_defs[-1]) + + for item in session.items: + write_item(item) + + def showfixtures(config): from _pytest.main import wrap_session return wrap_session(config, _showfixtures_main) From bbc6c184484c246717417efbb07970776df399b1 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 12 Jun 2016 00:26:32 +0100 Subject: [PATCH 3/5] Add changelog entry for new cli flag --- CHANGELOG.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index da3918251..7563ac675 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -34,6 +34,11 @@ * New ``pytest_make_parametrize_id`` hook. Thanks `@palaviv`_ for the PR. +* New cli flag ``--fixtures-per-test`` that shows which fixtures are being used + for each selected test item. Features doc strings of fixtures by default. + Can also show where fixtures are defined if combined with ``-v``. + Thanks `@hackebrot`_ for the PR. + **Changes** * Fix (`#1351`_): From b99aace8a91b442a9c6e25081369fbd0fb15f96d Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 12 Jun 2016 00:52:03 +0100 Subject: [PATCH 4/5] Fix py26 by using indices in str.format --- _pytest/python.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index a9243b36a..03792099a 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1229,12 +1229,12 @@ def _show_fixtures_per_test(config, session): return if verbose > 0: bestrel = get_best_rel(fixture_def.func) - funcargspec = "{} -- {}".format(argname, bestrel) + funcargspec = "{0} -- {1}".format(argname, bestrel) else: funcargspec = argname tw.line(funcargspec, green=True) - INDENT = ' {}' + INDENT = ' {0}' fixture_doc = fixture_def.func.__doc__ if fixture_doc: @@ -1252,8 +1252,8 @@ def _show_fixtures_per_test(config, session): bestrel = get_best_rel(item.function) tw.line() - tw.sep('-', 'fixtures used by {}'.format(item.name)) - tw.sep('-', 'from {}'.format(bestrel)) + tw.sep('-', 'fixtures used by {0}'.format(item.name)) + tw.sep('-', 'from {0}'.format(bestrel)) for argname, fixture_defs in sorted(name2fixturedefs.items()): assert fixture_defs is not None if not fixture_defs: From adc50ac72f797e858aac2a49a03727b8b114e118 Mon Sep 17 00:00:00 2001 From: Raphael Pierzina Date: Sun, 12 Jun 2016 15:58:32 +0100 Subject: [PATCH 5/5] Change format for test function locations --- _pytest/python.py | 2 +- testing/python/show_fixtures_per_test.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/_pytest/python.py b/_pytest/python.py index 03792099a..29b80b27a 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1253,7 +1253,7 @@ def _show_fixtures_per_test(config, session): tw.line() tw.sep('-', 'fixtures used by {0}'.format(item.name)) - tw.sep('-', 'from {0}'.format(bestrel)) + tw.sep('-', '({0})'.format(bestrel)) for argname, fixture_defs in sorted(name2fixturedefs.items()): assert fixture_defs is not None if not fixture_defs: diff --git a/testing/python/show_fixtures_per_test.py b/testing/python/show_fixtures_per_test.py index 3a34a513d..18563e818 100644 --- a/testing/python/show_fixtures_per_test.py +++ b/testing/python/show_fixtures_per_test.py @@ -25,7 +25,7 @@ def test_fixtures_in_module(testdir): result.stdout.fnmatch_lines([ '*fixtures used by test_arg1*', - '*from test_fixtures_in_module.py:9*', + '*(test_fixtures_in_module.py:9)*', 'arg1', ' arg1 docstring', ]) @@ -58,11 +58,11 @@ def test_fixtures_in_conftest(testdir): result.stdout.fnmatch_lines([ '*fixtures used by test_arg2*', - '*from test_fixtures_in_conftest.py:2*', + '*(test_fixtures_in_conftest.py:2)*', 'arg2', ' arg2 docstring', '*fixtures used by test_arg3*', - '*from test_fixtures_in_conftest.py:4*', + '*(test_fixtures_in_conftest.py:4)*', 'arg1', ' arg1 docstring', 'arg2', @@ -96,7 +96,7 @@ def test_should_show_fixtures_used_by_test(testdir): result.stdout.fnmatch_lines([ '*fixtures used by test_args*', - '*from test_should_show_fixtures_used_by_test.py:6*', + '*(test_should_show_fixtures_used_by_test.py:6)*', 'arg1', ' arg1 from testmodule', 'arg2', @@ -127,7 +127,7 @@ def test_verbose_include_private_fixtures_and_loc(testdir): result.stdout.fnmatch_lines([ '*fixtures used by test_args*', - '*from test_verbose_include_private_fixtures_and_loc.py:6*', + '*(test_verbose_include_private_fixtures_and_loc.py:6)*', '_arg1 -- conftest.py:3', ' _arg1 from conftest', 'arg2 -- conftest.py:6',