Skip to content

Commit 2af3a7a

Browse files
Merge pull request #1519 from omarkohl/pytest_skip_decorator
Raise CollectError if pytest.skip() is called during collection
2 parents 35cd12e + b3615ac commit 2af3a7a

File tree

8 files changed

+87
-53
lines changed

8 files changed

+87
-53
lines changed

CHANGELOG.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,24 @@
1+
3.0.0.dev1
2+
==========
3+
4+
**Changes**
5+
6+
*
7+
8+
*
9+
10+
*
11+
12+
* Fix (`#607`_): pytest.skip() is no longer allowed at module level to
13+
prevent misleading use as test function decorator. When used at a module
14+
level an error will be raised during collection.
15+
Thanks `@omarkohl`_ for the complete PR (`#1519`_).
16+
17+
*
18+
19+
.. _#607: https://github.com/pytest-dev/pytest/issues/607
20+
.. _#1519: https://github.com/pytest-dev/pytest/pull/1519
21+
122
2.10.0.dev1
223
===========
324

_pytest/python.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,12 @@ def _importtestmodule(self):
656656
"Make sure your test modules/packages have valid Python names."
657657
% (self.fspath, exc or exc_class)
658658
)
659+
except _pytest.runner.Skipped:
660+
raise self.CollectError(
661+
"Using @pytest.skip outside a test (e.g. as a test function "
662+
"decorator) is not allowed. Use @pytest.mark.skip or "
663+
"@pytest.mark.skipif instead."
664+
)
659665
#print "imported test module", mod
660666
self.config.pluginmanager.consider_module(mod)
661667
return mod

testing/test_junitxml.py

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# -*- coding: utf-8 -*-
22

33
from xml.dom import minidom
4-
from _pytest.main import EXIT_NOTESTSCOLLECTED
54
import py
65
import sys
76
import os
@@ -158,6 +157,47 @@ def test_skip():
158157
snode = tnode.find_first_by_tag("skipped")
159158
snode.assert_attr(type="pytest.skip", message="hello23", )
160159

160+
def test_mark_skip_contains_name_reason(self, testdir):
161+
testdir.makepyfile("""
162+
import pytest
163+
@pytest.mark.skip(reason="hello24")
164+
def test_skip():
165+
assert True
166+
""")
167+
result, dom = runandparse(testdir)
168+
assert result.ret == 0
169+
node = dom.find_first_by_tag("testsuite")
170+
node.assert_attr(skips=1)
171+
tnode = node.find_first_by_tag("testcase")
172+
tnode.assert_attr(
173+
file="test_mark_skip_contains_name_reason.py",
174+
line="1",
175+
classname="test_mark_skip_contains_name_reason",
176+
name="test_skip")
177+
snode = tnode.find_first_by_tag("skipped")
178+
snode.assert_attr(type="pytest.skip", message="hello24", )
179+
180+
def test_mark_skipif_contains_name_reason(self, testdir):
181+
testdir.makepyfile("""
182+
import pytest
183+
GLOBAL_CONDITION = True
184+
@pytest.mark.skipif(GLOBAL_CONDITION, reason="hello25")
185+
def test_skip():
186+
assert True
187+
""")
188+
result, dom = runandparse(testdir)
189+
assert result.ret == 0
190+
node = dom.find_first_by_tag("testsuite")
191+
node.assert_attr(skips=1)
192+
tnode = node.find_first_by_tag("testcase")
193+
tnode.assert_attr(
194+
file="test_mark_skipif_contains_name_reason.py",
195+
line="2",
196+
classname="test_mark_skipif_contains_name_reason",
197+
name="test_skip")
198+
snode = tnode.find_first_by_tag("skipped")
199+
snode.assert_attr(type="pytest.skip", message="hello25", )
200+
161201
def test_classname_instance(self, testdir):
162202
testdir.makepyfile("""
163203
class TestClass:
@@ -351,23 +391,6 @@ def test_collect_error(self, testdir):
351391
fnode.assert_attr(message="collection failure")
352392
assert "SyntaxError" in fnode.toxml()
353393

354-
def test_collect_skipped(self, testdir):
355-
testdir.makepyfile("import pytest; pytest.skip('xyz')")
356-
result, dom = runandparse(testdir)
357-
assert result.ret == EXIT_NOTESTSCOLLECTED
358-
node = dom.find_first_by_tag("testsuite")
359-
node.assert_attr(skips=1, tests=1)
360-
tnode = node.find_first_by_tag("testcase")
361-
tnode.assert_attr(
362-
file="test_collect_skipped.py",
363-
name="test_collect_skipped")
364-
365-
# pytest doesn't give us a line here.
366-
assert tnode["line"] is None
367-
368-
fnode = tnode.find_first_by_tag("skipped")
369-
fnode.assert_attr(message="collection skipped")
370-
371394
def test_unicode(self, testdir):
372395
value = 'hx\xc4\x85\xc4\x87\n'
373396
testdir.makepyfile("""

testing/test_resultlog.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -83,19 +83,10 @@ def getresultlog(self, testdir, arg):
8383

8484
def test_collection_report(self, testdir):
8585
ok = testdir.makepyfile(test_collection_ok="")
86-
skip = testdir.makepyfile(test_collection_skip=
87-
"import pytest ; pytest.skip('hello')")
8886
fail = testdir.makepyfile(test_collection_fail="XXX")
8987
lines = self.getresultlog(testdir, ok)
9088
assert not lines
9189

92-
lines = self.getresultlog(testdir, skip)
93-
assert len(lines) == 2
94-
assert lines[0].startswith("S ")
95-
assert lines[0].endswith("test_collection_skip.py")
96-
assert lines[1].startswith(" ")
97-
assert lines[1].endswith("test_collection_skip.py:1: Skipped: hello")
98-
9990
lines = self.getresultlog(testdir, fail)
10091
assert lines
10192
assert lines[0].startswith("F ")

testing/test_runner.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -365,18 +365,6 @@ class TestClass:
365365
assert res[0].name == "test_func1"
366366
assert res[1].name == "TestClass"
367367

368-
def test_skip_at_module_scope(self, testdir):
369-
col = testdir.getmodulecol("""
370-
import pytest
371-
pytest.skip("hello")
372-
def test_func():
373-
pass
374-
""")
375-
rep = main.collect_one_node(col)
376-
assert not rep.failed
377-
assert not rep.passed
378-
assert rep.skipped
379-
380368

381369
reporttypes = [
382370
runner.BaseReport,

testing/test_session.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,6 @@ def test_method_one(self):
174174
class TestY(TestX):
175175
pass
176176
""",
177-
test_two="""
178-
import pytest
179-
pytest.skip('xxx')
180-
""",
181177
test_three="xxxdsadsadsadsa",
182178
__init__=""
183179
)
@@ -189,11 +185,9 @@ class TestY(TestX):
189185
started = reprec.getcalls("pytest_collectstart")
190186
finished = reprec.getreports("pytest_collectreport")
191187
assert len(started) == len(finished)
192-
assert len(started) == 8 # XXX extra TopCollector
188+
assert len(started) == 7 # XXX extra TopCollector
193189
colfail = [x for x in finished if x.failed]
194-
colskipped = [x for x in finished if x.skipped]
195190
assert len(colfail) == 1
196-
assert len(colskipped) == 1
197191

198192
def test_minus_x_import_error(self, testdir):
199193
testdir.makepyfile(__init__="")

testing/test_skipping.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,6 @@ class TestClass:
682682
def test_method(self):
683683
doskip()
684684
""",
685-
test_two = """
686-
from conftest import doskip
687-
doskip()
688-
""",
689685
conftest = """
690686
import pytest
691687
def doskip():
@@ -694,7 +690,7 @@ def doskip():
694690
)
695691
result = testdir.runpytest('--report=skipped')
696692
result.stdout.fnmatch_lines([
697-
"*SKIP*3*conftest.py:3: test",
693+
"*SKIP*2*conftest.py:3: test",
698694
])
699695
assert result.ret == 0
700696

@@ -941,3 +937,19 @@ def pytest_collect_file(path, parent):
941937
assert not failed
942938
xfailed = [r for r in skipped if hasattr(r, 'wasxfail')]
943939
assert xfailed
940+
941+
942+
def test_module_level_skip_error(testdir):
943+
"""
944+
Verify that using pytest.skip at module level causes a collection error
945+
"""
946+
testdir.makepyfile("""
947+
import pytest
948+
@pytest.skip
949+
def test_func():
950+
assert True
951+
""")
952+
result = testdir.runpytest()
953+
result.stdout.fnmatch_lines(
954+
"*Using @pytest.skip outside a test * is not allowed*"
955+
)

testing/test_terminal.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,7 @@ def test_collectonly_skipped_module(self, testdir):
223223
""")
224224
result = testdir.runpytest("--collect-only", "-rs")
225225
result.stdout.fnmatch_lines([
226-
"SKIP*hello*",
227-
"*1 skip*",
226+
"*ERROR collecting*",
228227
])
229228

230229
def test_collectonly_failed_module(self, testdir):

0 commit comments

Comments
 (0)