Skip to content

Commit

Permalink
Add --used-fixtures command
Browse files Browse the repository at this point in the history
  • Loading branch information
malthejorgensen committed Dec 11, 2022
1 parent e7d25cc commit 16f472f
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 6 deletions.
72 changes: 66 additions & 6 deletions pytest_deadfixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"Hey there, I believe the following fixture(s) are not being used:"
)
UNUSED_FIXTURES_NOT_FOUND_HEADLINE = "Cool, every declared fixture is being used."
USED_FIXTURES_FOUND_HEADLINE = (
"Hey there, I believe the following fixture(s) are being used:"
)
USED_FIXTURES_NOT_FOUND_HEADLINE = "We could not find any fixtures being used"

EXIT_CODE_ERROR = 11
EXIT_CODE_SUCCESS = 0
Expand All @@ -23,6 +27,8 @@

CachedFixture = namedtuple("CachedFixture", "fixturedef, relpath, result")

UsedFixture = namedtuple("UsedFixture", "relpath, argname, fixturedef")


def pytest_addoption(parser):
group = parser.getgroup("deadfixtures")
Expand All @@ -40,6 +46,13 @@ def pytest_addoption(parser):
default=False,
help="Show duplicated fixtures",
)
group.addoption(
"--used-fixtures",
action="store_true",
dest="usedfixtures",
default=False,
help="Show fixtures being used",
)


def pytest_cmdline_main(config):
Expand All @@ -49,6 +62,10 @@ def pytest_cmdline_main(config):
if _show_dead_fixtures(config):
return EXIT_CODE_ERROR
return EXIT_CODE_SUCCESS
elif config.option.usedfixtures:
if _show_used_fixtures(config):
return EXIT_CODE_ERROR
return EXIT_CODE_SUCCESS


def _show_dead_fixtures(config):
Expand All @@ -57,6 +74,12 @@ def _show_dead_fixtures(config):
return wrap_session(config, show_dead_fixtures)


def _show_used_fixtures(config):
from _pytest.main import wrap_session

return wrap_session(config, show_used_fixtures)


def get_best_relpath(func, curdir):
loc = getlocation(func, curdir)
return curdir.bestrelpath(loc)
Expand Down Expand Up @@ -98,8 +121,10 @@ def get_fixtures(session):
return available


def get_used_fixturesdefs(session):
fixturesdefs = []
def get_used_fixtures(session):
used = []
seen = set()
curdir = py.path.local()
for test_function in session.items:
try:
info = test_function._fixtureinfo
Expand All @@ -113,8 +138,27 @@ def get_used_fixturesdefs(session):
for _, fixturedefs in sorted(info.name2fixturedefs.items()):
if fixturedefs is None:
continue
fixturesdefs.append(fixturedefs[-1])
return fixturesdefs

for fixturedef in fixturedefs:
loc = getlocation(fixturedef.func, curdir)
if (fixturedef.argname, loc) in seen:
continue

seen.add((fixturedef.argname, loc))

module = fixturedef.func.__module__

if (
not module.startswith("_pytest.")
and not module.startswith("pytest_")
and not ("site-packages" in loc)
):
used.append(
UsedFixture(
curdir.bestrelpath(loc), fixturedef.argname, fixturedef
)
)
return used


def write_docstring(tw, doc):
Expand Down Expand Up @@ -198,13 +242,13 @@ def show_dead_fixtures(config, session):
tw = _pytest.config.create_terminal_writer(config)
show_fixture_doc = config.getvalue("show_fixture_doc")

used_fixtures = get_used_fixturesdefs(session)
used_fixturedefs = [f.fixturedef for f in get_used_fixtures(session)]
available_fixtures = get_fixtures(session)

unused_fixtures = [
fixture
for fixture in available_fixtures
if fixture.fixturedef not in used_fixtures
if fixture.fixturedef not in used_fixturedefs
]

tw.line()
Expand All @@ -214,3 +258,19 @@ def show_dead_fixtures(config, session):
else:
tw.line(UNUSED_FIXTURES_NOT_FOUND_HEADLINE, green=True)
return unused_fixtures


def show_used_fixtures(config, session):
session.perform_collect()
tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose")

used_fixtures = get_used_fixtures(session)

tw.line()
if used_fixtures:
tw.line(USED_FIXTURES_FOUND_HEADLINE, green=True)
write_fixtures(tw, used_fixtures, verbose)
else:
tw.line(USED_FIXTURES_NOT_FOUND_HEADLINE, red=True)
return used_fixtures
36 changes: 36 additions & 0 deletions tests/test_deadfixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def test_simple():

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("autouse_fixture", "test_dont_list_autouse_fixture")

assert message in result.stdout.str()


def test_dont_list_same_file_fixture(pytester, message_template):
pytester.makepyfile(
Expand All @@ -90,6 +95,13 @@ def test_simple(same_file_fixture):

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"same_file_fixture", "test_dont_list_same_file_fixture"
)

assert message in result.stdout.str()


def test_list_same_file_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand All @@ -114,6 +126,13 @@ def test_simple():

assert message in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"same_file_fixture", "test_list_same_file_unused_fixture"
)

assert message not in result.stdout.str()


def test_list_same_file_multiple_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -176,6 +195,11 @@ def test_conftest_fixture(conftest_fixture):

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("conftest_fixture", "conftest")

assert message in result.stdout.str()


def test_list_conftest_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -204,6 +228,11 @@ def test_conftest_fixture():

assert message in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("conftest_fixture", "conftest")

assert message not in result.stdout.str()


def test_list_conftest_multiple_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -266,6 +295,13 @@ def test_decorator_usefixtures():

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"decorator_usefixtures", "test_dont_list_decorator_usefixtures"
)

assert message in result.stdout.str()


def test_write_docs_when_verbose(pytester):
pytester.makepyfile(
Expand Down

0 comments on commit 16f472f

Please sign in to comment.