Skip to content

Commit d541ae9

Browse files
committed
Avoid silently skipped tests
1 parent fe7bde7 commit d541ae9

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

hypothesis-python/RELEASE.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
RELEASE_TYPE: minor
2+
3+
This release raises :class:`~unittest.SkipTest` for which never executed any
4+
examples, for example because the :obj:`~hypothesis.settings.phases` setting
5+
excluded the :obj:`~hypothesis.Phase.explicit`, :obj:`~hypothesis.Phase.reuse`,
6+
and :obj:`~hypothesis.Phase.generate` phases. This helps to avoid cases where
7+
broken tests appear to pass, because they didn't actually execute (:issue:`3328`).

hypothesis-python/src/hypothesis/core.py

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import sys
1919
import time
2020
import types
21+
import unittest
2122
import warnings
2223
import zlib
2324
from collections import defaultdict
@@ -556,6 +557,7 @@ def __init__(
556557
self.__was_flaky = False
557558
self.random = random
558559
self.__test_runtime = None
560+
self.ever_executed = False
559561

560562
self.is_find = getattr(wrapped_test, "_hypothesis_internal_is_find", False)
561563
self.wrapped_test = wrapped_test
@@ -586,6 +588,7 @@ def execute_once(
586588
swallowed the corresponding control exception.
587589
"""
588590

591+
self.ever_executed = True
589592
data.is_find = self.is_find
590593

591594
text_repr = None
@@ -1189,9 +1192,17 @@ def wrapped_test(*arguments, **kwargs):
11891192
# The next step is to use the Conjecture engine to run the test on
11901193
# many different inputs.
11911194

1195+
ran_explicit_examples = Phase.explicit in state.settings.phases and getattr(
1196+
wrapped_test, "hypothesis_explicit_examples", ()
1197+
)
1198+
SKIP_BECAUSE_NO_EXAMPLES = unittest.SkipTest(
1199+
"Hypothesis has been told to run no examples for this test."
1200+
)
11921201
if not (
11931202
Phase.reuse in settings.phases or Phase.generate in settings.phases
11941203
):
1204+
if not ran_explicit_examples:
1205+
raise SKIP_BECAUSE_NO_EXAMPLES
11951206
return
11961207

11971208
try:
@@ -1236,6 +1247,9 @@ def wrapped_test(*arguments, **kwargs):
12361247
)
12371248
raise the_error_hypothesis_found
12381249

1250+
if not (ran_explicit_examples or state.ever_executed):
1251+
raise SKIP_BECAUSE_NO_EXAMPLES
1252+
12391253
def _get_fuzz_target() -> Callable[
12401254
[Union[bytes, bytearray, memoryview, BinaryIO]], Optional[bytes]
12411255
]:

hypothesis-python/tests/cover/test_core.py

+33-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
99
# obtain one at https://mozilla.org/MPL/2.0/.
1010

11+
import unittest
12+
1113
import pytest
1214
from _pytest.outcomes import Failed, Skipped
1315

14-
from hypothesis import find, given, reject, settings, strategies as s
16+
from hypothesis import Phase, example, find, given, reject, settings, strategies as s
17+
from hypothesis.database import InMemoryExampleDatabase
1518
from hypothesis.errors import InvalidArgument, NoSuchExample, Unsatisfiable
1619

1720

@@ -111,3 +114,32 @@ def test_method_with_bad_strategy(self, x):
111114
instance = TestStrategyValidation()
112115
with pytest.raises(InvalidArgument):
113116
instance.test_method_with_bad_strategy()
117+
118+
119+
@example(1)
120+
@given(s.integers())
121+
@settings(phases=[Phase.target, Phase.shrink, Phase.explain])
122+
def no_phases(_):
123+
raise Exception
124+
125+
126+
@given(s.integers())
127+
@settings(phases=[Phase.explicit])
128+
def no_explicit(_):
129+
raise Exception
130+
131+
132+
@given(s.integers())
133+
@settings(phases=[Phase.reuse], database=InMemoryExampleDatabase())
134+
def empty_db(_):
135+
raise Exception
136+
137+
138+
@pytest.mark.parametrize(
139+
"test_fn",
140+
[no_phases, no_explicit, empty_db],
141+
ids=lambda t: t.__name__,
142+
)
143+
def test_non_executed_tests_raise_skipped(test_fn):
144+
with pytest.raises(unittest.SkipTest):
145+
test_fn()

hypothesis-python/tests/cover/test_fuzz_one_input.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# obtain one at https://mozilla.org/MPL/2.0/.
1010

1111
import io
12+
import unittest
1213
from operator import attrgetter
1314

1415
import pytest
@@ -45,7 +46,8 @@ def test(s):
4546

4647
# Before running fuzz_one_input, there's nothing in `db`, and so the test passes
4748
# (because example generation is disabled by the custom settings)
48-
test()
49+
with pytest.raises(unittest.SkipTest): # because this generates no examples
50+
test()
4951
assert len(seen) == 0
5052

5153
# If we run a lot of random bytestrings through fuzz_one_input, we'll eventually

0 commit comments

Comments
 (0)