diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 328cbb7..9cbb035 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,11 +13,11 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: matrix: - python: ['3.7', '3.8', '3.9', '3.10', 'py3.11', 'pypy3.9'] + python: ['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy3.9'] steps: - uses: actions/checkout@v3 @@ -36,31 +36,31 @@ jobs: - name: Test with Python 3.7 if: matrix.python == '3.7' - run: tox -e 'py37-pytest{4,5,60,61,62,70,71,72,73}' + run: tox run -x "tox.envlist=py37-pytest{4,5,60,61,62,70,71,72,73}" - name: Test with Python 3.8 if: matrix.python == '3.8' - run: tox -e 'py38-pytest{4,5,60,61,62,70,71,72,73}' + run: tox run -x "tox.envlist=py38-pytest{4,5,60,61,62,70,71,72,73}" - name: Test with Python 3.9 if: matrix.python == '3.9' - run: tox -e 'py39-pytest{4,5,60,61,62,70,71,72,73}' + run: tox run -x "tox.envlist=py39-pytest{4,5,60,61,62,70,71,72,73}" - name: Test with Python 3.10 if: matrix.python == '3.10' - run: tox -e 'py310-pytest{62,70,71,72,73}' + run: tox run -x "tox.envlist=py310-pytest{62,70,71,72,73}" - name: Test with Python 3.11 if: matrix.python == '3.11' - run: tox -e 'py311-pytest{73}' + run: tox run -x "tox.envlist=spy311-pytest{73}" - name: Test with PyPy 3.9 if: matrix.python == 'pypy3.9' - run: tox -e 'pypy39-pytest{4,5,60,61,62,70,71,72,73}' + run: tox run -x "tox.envlist=pypy39-pytest{4,5,60,61,62,70,71,72,73}" - name: Linting with Flake8 if: matrix.python == '3.10' - run: tox -e flake8 + run: tox run -e flake8 deploy: if: | diff --git a/test/conftest.py b/test/conftest.py new file mode 100644 index 0000000..ad4f361 --- /dev/null +++ b/test/conftest.py @@ -0,0 +1,3 @@ +"""Global fixtures for testing the plugin""" + +pytest_plugins = ["pytester"] diff --git a/test/test_collect.py b/test/test_collect.py index 47818a0..c9ade75 100644 --- a/test/test_collect.py +++ b/test/test_collect.py @@ -1,13 +1,9 @@ -import re +"""Test collection of test functions""" -from util import assert_outcomes, Source -pytest_plugins = 'pytester' - - -def test_collect(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" +def test_collect_only(testdir): + testdir.makepyfile( + """ def describe_something(): def is_foo(): pass @@ -23,27 +19,28 @@ def foo_not_collected(): pass def test_something(): pass - """)) + """) result = testdir.runpytest('--collectonly') - - expected_regex = map(re.compile, [ - r"collected 4 item(s)?", - r"\s*", - r"\s*", - r"\s*", - r"\s*", - r"\s*", - r"\s*", - r"\s*", - ]) - for line in expected_regex: - assert any([line.match(r) is not None for r in result.outlines]) + result.assert_outcomes() + + output = '\n'.join(filter(None, result.outlines)) + assert """ +collected 4 items + + + + + + + + +""" in output def test_describe_evaluated_once(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ count = 0 def describe_is_evaluated_only_once(): global count @@ -55,7 +52,7 @@ def two(): def describe_nested(): def three(): assert count == 1 - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, passed=3) + result.assert_outcomes(passed=3) diff --git a/test/test_custom_prefix.py b/test/test_custom_prefix.py deleted file mode 100644 index 163193c..0000000 --- a/test/test_custom_prefix.py +++ /dev/null @@ -1,33 +0,0 @@ -import re - -from util import Source - -pytest_plugins = 'pytester' - -ini = """ -[pytest] -describe_prefixes = foo bar -""" - - -def test_collect_custom_prefix(testdir): - testdir.makeini(ini) - - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" - def foo_scope(): - def bar_context(): - def passes(): - pass - """)) - - result = testdir.runpytest('--collectonly') - expected_lines = map(re.compile, [ - r"collected 1 item(s)?", - r"\s*", - r"\s*", - r"\s*", - r"\s*", - ]) - for line in expected_lines: - assert any([line.match(r) is not None for r in result.outlines]) diff --git a/test/test_fixtures.py b/test/test_fixtures.py index 0e4cfe4..eeb21af 100644 --- a/test/test_fixtures.py +++ b/test/test_fixtures.py @@ -1,11 +1,9 @@ -from util import assert_outcomes, Source - -pytest_plugins = 'pytester' +"""Test with fixtures""" def test_can_access_local_fixture(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_something(): @@ -15,15 +13,15 @@ def thing(): def thing_is_42(thing): assert thing == 42 - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=1) + result.assert_outcomes(passed=1) def test_can_access_fixture_from_nested_scope(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_something(): @@ -34,15 +32,15 @@ def thing(): def describe_a_nested_scope(): def thing_is_42(thing): assert thing == 42 - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=1) + result.assert_outcomes(passed=1) def test_local_fixture_overrides(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.fixture @@ -60,7 +58,7 @@ def thing_is_42(thing): def thing_is_12(thing): assert thing == 12 - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) diff --git a/test/test_marks.py b/test/test_marks.py index ad50e0a..bfa2e3d 100644 --- a/test/test_marks.py +++ b/test/test_marks.py @@ -1,11 +1,18 @@ -from util import assert_outcomes, Source +"""Test mark decorator""" -pytest_plugins = 'pytester' + +def assert_outcomes(result, **kwargs): + """Get all relevant outcomes""" + assert { + key: value + for key, value in result.parseoutcomes().items() + if key != 'seconds' + } == kwargs def test_special_marks(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_marks(): @@ -24,15 +31,15 @@ def skipped(): @pytest.mark.parametrize('foo', (1, 2, 3)) def isint(foo): assert foo == int(foo) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=3, xfailed=1, xpassed=1, skipped=1) + result.assert_outcomes(passed=3, xfailed=1, xpassed=1, skipped=1) def test_multiple_variables_parametrize(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_marks(): @@ -50,15 +57,15 @@ def isint_list_names(foo, bar): def isint_tuple_names(foo, bar): assert foo == int(foo) assert bar == int(bar) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=6) + result.assert_outcomes(passed=6) def test_cartesian_parametrize(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_marks(): @@ -68,15 +75,15 @@ def describe_marks(): def isint(foo, bar): assert foo == int(foo) assert bar == int(bar) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=9) + result.assert_outcomes(passed=9) def test_parametrize_applies_to_describe(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.mark.parametrize('foo', (1, 2, 3)) @@ -93,15 +100,15 @@ def isint2(foo): def describe_nested(): def isint3(foo): assert foo == int(foo) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=15) + result.assert_outcomes(passed=15) def test_cartesian_parametrize_on_describe(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.mark.parametrize('foo', (1, 2, 3)) @@ -111,15 +118,15 @@ def describe_marks(): def isint(foo, bar): assert foo == int(foo) assert bar == int(bar) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=9) + result.assert_outcomes(passed=9) def test_parametrize_with_shared(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest from pytest import fixture from pytest_describe import behaves_like @@ -142,15 +149,15 @@ def describe_something_that_barks(): @fixture def sound(foo): return foo - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=6) + result.assert_outcomes(passed=6) def test_parametrize_with_shared_but_different_values(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest from pytest import fixture from pytest_describe import behaves_like @@ -175,15 +182,15 @@ def describe_something_that_barks(): @fixture def sound(foo): return ('bark', foo) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=6) + result.assert_outcomes(passed=6) def test_coincident_parametrize_at_top(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.mark.parametrize('foo', (1, 2, 3)) @@ -198,32 +205,41 @@ def isint(foo, bar): def describe_marks2(): def isint2(foo): assert foo == int(foo) - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=12) + result.assert_outcomes(passed=12) def test_keywords(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest def describe_a(): - @pytest.mark.foo def foo_test(): pass - @pytest.mark.bar def bar_test(): pass - """)) + """) result = testdir.runpytest('-k', 'foo') - assert_outcomes(result, passed=1, deselected=1) - - -def test_marks(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + try: + result.assert_outcomes(passed=1, deselected=1) + except TypeError: # pytest < 7.0 + assert_outcomes(result, passed=1, deselected=1) + + +def test_custom_markers(testdir): + testdir.makeini( + """ + [pytest] + markers = + foo + bar + """) + + testdir.makepyfile( + """ import pytest def describe_a(): @pytest.mark.foo @@ -232,15 +248,18 @@ def foo_test(): @pytest.mark.bar def bar_test(): pass - """)) + """) result = testdir.runpytest('-m', 'foo') - assert_outcomes(result, passed=1, deselected=1) + try: + result.assert_outcomes(passed=1, deselected=1) + except TypeError: # pytest < 7.0 + assert_outcomes(result, passed=1, deselected=1) def test_module_marks(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest pytestmark = [ pytest.mark.foo ] def describe_a(): @@ -248,15 +267,15 @@ def describe_a(): def describe_b(): def a_test(): pass - """)) + """) result = testdir.runpytest('-m', 'foo') - assert_outcomes(result, passed=1) + result.assert_outcomes(passed=1) def test_mark_at_describe_function(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.mark.foo def describe_foo(): @@ -266,15 +285,15 @@ def a_test(): @pytest.mark.bar def b_test(): pass - """)) + """) result = testdir.runpytest('-m', 'foo') - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) def test_mark_stacking(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ import pytest @pytest.fixture() def get_marks(request): @@ -293,7 +312,7 @@ def all_marks_are_chained(get_marks): ('baz', 'all_marks_are_chained'), ('bar', 'all_marks_are_chained'), ('foo', 'describe_marks')] - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) diff --git a/test/test_output.py b/test/test_output.py index 5a612f8..4436d62 100644 --- a/test/test_output.py +++ b/test/test_output.py @@ -1,11 +1,9 @@ -from util import Source - -pytest_plugins = 'pytester' +"""Test verbose output""" def test_verbose_output(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ def describe_something(): def describe_nested_ok(): def passes(): @@ -13,14 +11,20 @@ def passes(): def describe_nested_bad(): def fails(): assert False - """)) + """ + ) + + result = testdir.runpytest("-v") + + result.assert_outcomes(passed=1, failed=1) + + output = [ + ' '.join(line.split('::', 2)[2].split()) + for line in result.outlines + if line.startswith('test_verbose_output.py::describe_something::') + ] - result = testdir.runpytest('-v') - expected = [ - 'a_dir/test_a.py::describe_something::describe_nested_bad::' - 'fails FAILED', - 'a_dir/test_a.py::describe_something::describe_nested_ok::' - 'passes PASSED', + assert output == [ + "describe_nested_ok::passes PASSED [ 50%]", + "describe_nested_bad::fails FAILED [100%]", ] - for line in expected: - assert any(out for out in result.outlines if out.startswith(line)) diff --git a/test/test_prefix.py b/test/test_prefix.py new file mode 100644 index 0000000..4d5ade4 --- /dev/null +++ b/test/test_prefix.py @@ -0,0 +1,29 @@ +"""Test custom prefixes""" + + +def test_collect_custom_prefix(testdir): + testdir.makeini( + """ + [pytest] + describe_prefixes = foo bar + """) + + testdir.makepyfile( + """ + def foo_scope(): + def bar_context(): + def passes(): + pass + """) + + result = testdir.runpytest('--collectonly') + result.assert_outcomes() + + output = '\n'.join(filter(None, result.outlines)) + assert """ +collected 1 item + + + + +""" in output diff --git a/test/test_shared.py b/test/test_shared.py index fd2da93..cfa6291 100644 --- a/test/test_shared.py +++ b/test/test_shared.py @@ -1,11 +1,9 @@ -from util import assert_outcomes, Source +"""Test shared behaviors""" -pytest_plugins = 'pytester' - -def test_shared_behavior(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" +def test_shared_behaviors(testdir): + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -24,15 +22,15 @@ def describe_something_that_barks(): @fixture def sound(): return "bark" - """)) + """) result = testdir.runpytest() - assert_outcomes(result, failed=1, passed=1) + result.assert_outcomes(failed=1, passed=1) def test_multiple_shared_behaviors(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -60,15 +58,15 @@ def describe_something_that_barks(): @fixture def sound(): return "bark" - """)) + """) result = testdir.runpytest() - assert_outcomes(result, failed=1, passed=3) + result.assert_outcomes(failed=1, passed=3) def test_fixture(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -83,15 +81,15 @@ def it_quacks(sound): @behaves_like(a_duck) def describe_a_normal_duck(): pass - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, passed=1) + result.assert_outcomes(passed=1) def test_override_fixture(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -108,15 +106,15 @@ def describe_something_that_barks(): @fixture def sound(): return "bark" - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, failed=1) + result.assert_outcomes(failed=1) def test_name_mangling(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -130,15 +128,15 @@ def describe_something(): foo = 4242 def it_does_something(): assert foo == 4242 - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) def test_nested_name_mangling(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -159,15 +157,15 @@ def it_does_something(): def describe_thing(): def it_does_something(): pass - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, passed=5) + result.assert_outcomes(passed=5) def test_evaluated_once(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_something.py').write(Source(""" + testdir.makepyfile( + """ from pytest import fixture from pytest_describe import behaves_like @@ -184,7 +182,7 @@ def describe_something(): @behaves_like(thing) def describe_something_else(): pass - """)) + """) result = testdir.runpytest('-v') - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) diff --git a/test/test_simple_execution.py b/test/test_simple.py similarity index 63% rename from test/test_simple_execution.py rename to test/test_simple.py index a997282..a8c10c0 100644 --- a/test/test_simple_execution.py +++ b/test/test_simple.py @@ -1,41 +1,39 @@ -from util import assert_outcomes, Source - -pytest_plugins = 'pytester' +"""Test simple execution""" def test_can_pass(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ def describe_something(): def passes(): assert True def describe_nested(): def passes_too(): assert True - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=2) + result.assert_outcomes(passed=2) def test_can_fail(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ def describe_something(): def fails(): assert False def describe_nested(): def fails_too(): assert False - """)) + """) result = testdir.runpytest() - assert_outcomes(result, failed=2) + result.assert_outcomes(failed=2) def test_can_fail_and_pass(testdir): - a_dir = testdir.mkpydir('a_dir') - a_dir.join('test_a.py').write(Source(""" + testdir.makepyfile( + """ def describe_something(): def describe_nested_ok(): def passes(): @@ -43,7 +41,7 @@ def passes(): def describe_nested_bad(): def fails(): assert False - """)) + """) result = testdir.runpytest() - assert_outcomes(result, passed=1, failed=1) + result.assert_outcomes(passed=1, failed=1) diff --git a/test/util.py b/test/util.py deleted file mode 100644 index cfbad46..0000000 --- a/test/util.py +++ /dev/null @@ -1,17 +0,0 @@ -try: - from _pytest._code import Source -except (ModuleNotFoundError, ImportError): # pytest < 7.2 - from py.code import Source - -__all__ = ["assert_outcomes", "Source"] - - -def assert_outcomes(result, **expected): - """Assert that the test outcomes match what is expected.""" - outcomes = result.parseoutcomes() - - for key in 'seconds', 'warning', 'warnings': - if key in outcomes: - del outcomes[key] - - assert outcomes == expected