diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ff55d8..e210d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # pytest-order Release Notes +## Unreleased + +### Fixes +- correctly handle combined class and test order markers, + see [#45](https://github.com/pytest-dev/pytest-order/issues/45) + ## [Version 1.0.0](https://pypi.org/project/pytest-order/1.0.0/) (2021-05-30) First Python 3 only version. diff --git a/pytest_order/__init__.py b/pytest_order/__init__.py index 5becc17..4930cac 100644 --- a/pytest_order/__init__.py +++ b/pytest_order/__init__.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "1.1.dev0" diff --git a/pytest_order/sorter.py b/pytest_order/sorter.py index 722d2bf..c9e34cd 100644 --- a/pytest_order/sorter.py +++ b/pytest_order/sorter.py @@ -128,7 +128,7 @@ def mark_binning( if has_dependency or self.settings.auto_mark_dep: self.handle_dependency_mark(item, has_order, dep_marks, aliases) if has_order: - self.handle_order_mark(item) + self.handle_order_marks(item) def handle_dependency_mark( self, @@ -160,8 +160,12 @@ def handle_dependency_mark( name_mark = item.node_id aliases[name_mark] = item - def handle_order_mark(self, item: Item) -> None: - mark = cast(Mark, item.item.get_closest_marker("order")) + def handle_order_marks(self, item: Item) -> None: + marks = item.item.iter_markers("order") + for mark in marks: + self.handle_order_mark(item, mark) + + def handle_order_mark(self, item: Item, mark: Mark) -> None: order = mark.args[0] if mark.args else mark.kwargs.get("index") if order is not None: if isinstance(order, int): @@ -171,7 +175,8 @@ def handle_order_mark(self, item: Item) -> None: else: warn("Unknown order attribute:'{}'".format(order)) order = None - item.order = order + if item.order is None: + item.order = order self.handle_relative_marks(item, mark) if order is not None: item.nr_rel_items = 0 diff --git a/tests/test_class_marks.py b/tests/test_class_marks.py index 4d6d491..1303418 100644 --- a/tests/test_class_marks.py +++ b/tests/test_class_marks.py @@ -179,3 +179,30 @@ def test_2(self): pass "Test1::test_1", "Test1::test_2", ] + + +def test_rel_class_mark_with_order_mark(item_names_for): + tests_content = ( + """ + import pytest + + class Test1: + def test_1(self): pass + + def test_2(self): pass + + @pytest.mark.order(before="Test1") + class Test2: + @pytest.mark.order(2) + def test_1(self): pass + + @pytest.mark.order(1) + def test_2(self): pass + """ + ) + assert item_names_for(tests_content) == [ + "Test2::test_2", + "Test2::test_1", + "Test1::test_1", + "Test1::test_2", + ] diff --git a/tests/test_order_group_scope_relative.py b/tests/test_order_group_scope_relative.py index 19177dd..3eb8152 100644 --- a/tests/test_order_group_scope_relative.py +++ b/tests/test_order_group_scope_relative.py @@ -133,3 +133,34 @@ def test_class_group_scope_module_scope(fixture_path): "test_rel4.py::test_one PASSED", "test_rel4.py::test_two PASSED", ]) + + +def test_rel_class_mark_with_order_mark(test_path): + test_path.makepyfile( + test_class_rel=""" + import pytest + + class Test1: + def test_1(self): pass + + @pytest.mark.order(1) + def test_2(self): pass + + @pytest.mark.order(before="Test1") + class Test2: + def test_1(self): pass + + @pytest.mark.order(1) + def test_2(self): pass + """ + ) + result = test_path.runpytest( + "-v", "--order-group-scope=class" + ) + result.assert_outcomes(passed=4, failed=0) + result.stdout.fnmatch_lines([ + "test_class_rel.py::Test2::test_2 PASSED", + "test_class_rel.py::Test2::test_1 PASSED", + "test_class_rel.py::Test1::test_2 PASSED", + "test_class_rel.py::Test1::test_1 PASSED", + ]) diff --git a/tests/test_relative_ordering.py b/tests/test_relative_ordering.py index d1a5f97..71d4719 100644 --- a/tests/test_relative_ordering.py +++ b/tests/test_relative_ordering.py @@ -322,6 +322,28 @@ def test_3(): assert item_names_for(test_content) == ["test_3", "test_2", "test_1"] +def test_multiple_markers(item_names_for): + test_content = ( + """ + import pytest + + def test_1(): + pass + + @pytest.mark.order(before="test_1") + @pytest.mark.order(2) + def test_2(): + pass + + @pytest.mark.order(1) + @pytest.mark.order(before="test_1") + def test_3(): + pass + """ + ) + assert item_names_for(test_content) == ["test_3", "test_2", "test_1"] + + def test_combined_markers3(item_names_for): test_content = ( """