Skip to content

Commit

Permalink
Add property testing example using hypothesis library
Browse files Browse the repository at this point in the history
- use `given` and `st.integers` to sample from a range of ints
- use `example` to explicitly include an input
- use `assume` to remove undesired inputs from sampling
- use `composite` to construct more complicated samples efficiently
  • Loading branch information
lkeegan committed Oct 9, 2023
1 parent 7dd0c91 commit b93dcb6
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ jobs:
# setuptools_scm requires a non-shallow clone of the repository
fetch-depth: 0

- uses: tlambert03/setup-qt-libs@v1

- name: Linux setup
if: runner.os == 'Linux'
# qt requires some system libraries on linux that are not installed by default
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ tests = [
"pytest-randomly",
"pytest-qt",
"pytest-xvfb",
"ipytest"
"ipytest",
"hypothesis",
]

# Command line scripts installed as part of the installation
Expand Down
42 changes: 42 additions & 0 deletions tests/test_board_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from __future__ import annotations
from effective_software_testing.board import Board
from hypothesis import given, assume, example
import hypothesis.strategies as st


# sample n from integers in the range 0 <= n <= 99
@given(n=st.integers(min_value=0, max_value=99))
@example(n=3) # always include n=3
def test_property_empty_board_game_not_over(n: int) -> None:
board = Board(n)
assert board.n == n
assert board.game_is_over is False


@given(n=st.integers(1, 12), x=st.integers(0, 11), y=st.integers(0, 11))
def test_property_empty_board_is_empty_with_assume(n: int, x: int, y: int) -> None:
assume(x < n) # if x >= n we re-sample n,x,y
assume(y < n)
# assume works but quickly gets inefficient if many inputs do not satisfy our assumptions
board = Board(n)
assert board.square(x, y) is None


# using composite is a more efficient way to sample from our desired distribution of values
@st.composite
def sample_valid_n_x_y(draw: st.DrawFn) -> tuple[int, int, int]:
max_board_n = 12
n = draw(st.integers(1, max_board_n))
x = draw(st.integers(0, n - 1))
y = draw(st.integers(0, n - 1))
return n, x, y


@given(n_x_y=sample_valid_n_x_y())
def test_property_empty_board_is_empty_with_composite(
n_x_y: tuple[int, int, int]
) -> None:
# no assume required here as all the x,y we generate are < n
n, x, y = n_x_y
board = Board(n)
assert board.square(x, y) is None

0 comments on commit b93dcb6

Please sign in to comment.