Skip to content

Commit 6df5cd3

Browse files
committed
Starter property-based test suite
1 parent 870e4ea commit 6df5cd3

File tree

6 files changed

+155
-0
lines changed

6 files changed

+155
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
*.py[cod]
22
__pycache__
33

4+
# example caches from Hypothesis
5+
.hypothesis/
6+
47
# temp files from docs build
58
doc/auto_gallery
69
doc/example.nc

.travis.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ matrix:
4949
env: CONDA_ENV=py36-netcdftime-dev
5050
- python: 3.5
5151
env: CONDA_ENV=docs
52+
- python: 3.6
53+
env: CONDA_ENV=py36-hypothesis
5254
allow_failures:
5355
- python: 3.6
5456
env:
@@ -108,6 +110,8 @@ script:
108110
- if [[ "$CONDA_ENV" == "docs" ]]; then
109111
conda install -c conda-forge sphinx_rtd_theme;
110112
sphinx-build -n -b html -d _build/doctrees doc _build/html;
113+
elif [[ "$CONDA_ENV" == "py36-hypothesis" ]]; then
114+
pytest properties ;
111115
else
112116
py.test xarray --cov=xarray --cov-config ci/.coveragerc --cov-report term-missing --verbose $EXTRA_FLAGS;
113117
fi

ci/requirements-py36-hypothesis.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: test_env
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- python=3.6
6+
- dask
7+
- distributed
8+
- h5py
9+
- h5netcdf
10+
- matplotlib
11+
- netcdf4
12+
- pytest
13+
- flake8
14+
- numpy
15+
- pandas
16+
- scipy
17+
- seaborn
18+
- toolz
19+
- rasterio
20+
- bottleneck
21+
- zarr
22+
- pip:
23+
- coveralls
24+
- pytest-cov
25+
- pydap
26+
- lxml
27+
- hypothesis

properties/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Property-based tests using Hypothesis
2+
3+
This directory contains property-based tests using a library
4+
called [Hypothesis](https://github.com/HypothesisWorks/hypothesis-python).
5+
6+
The property tests for Xarray are a work in progress - more are always welcome.
7+
They are stored in a separate directory because they tend to run more examples
8+
and thus take longer, and so that local development can run a test suite
9+
without needing to `pip install hypothesis`.
10+
11+
## Hang on, "property-based" tests?
12+
13+
Instead of making assertions about operations on a particular piece of
14+
data, you use Hypothesis to describe a *kind* of data, then make assertions
15+
that should hold for *any* example of this kind.
16+
17+
For example: "given a 2d ndarray of dtype uint8 `arr`,
18+
`xr.DataArray(arr).plot.imshow()` never raises an exception".
19+
20+
Hypothesis will then try many random examples, and report a minimised
21+
failing input for each error it finds.
22+
[See the docs for more info.](https://hypothesis.readthedocs.io/en/master/)

properties/test_encode_decode.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Property-based tests for encoding/decoding methods.
3+
4+
These ones pass, just as you'd hope!
5+
6+
"""
7+
from __future__ import absolute_import, division, print_function
8+
9+
from hypothesis import given, settings
10+
import hypothesis.strategies as st
11+
import hypothesis.extra.numpy as npst
12+
13+
import xarray as xr
14+
15+
# Run for a while - arrays are a bigger search space than usual
16+
settings.deadline = None
17+
18+
19+
an_array = npst.arrays(
20+
dtype=st.one_of(
21+
npst.unsigned_integer_dtypes(),
22+
npst.integer_dtypes(),
23+
npst.floating_dtypes(),
24+
),
25+
shape=npst.array_shapes(max_side=3), # max_side specified for performance
26+
)
27+
28+
29+
@given(st.data(), an_array)
30+
def test_CFMask_coder_roundtrip(data, arr):
31+
names = data.draw(st.lists(st.text(), min_size=arr.ndim,
32+
max_size=arr.ndim, unique=True).map(tuple))
33+
original = xr.Variable(names, arr)
34+
coder = xr.coding.variables.CFMaskCoder()
35+
roundtripped = coder.decode(coder.encode(original))
36+
xr.testing.assert_identical(original, roundtripped)
37+
38+
39+
@given(st.data(), an_array)
40+
def test_CFScaleOffset_coder_roundtrip(data, arr):
41+
names = data.draw(st.lists(st.text(), min_size=arr.ndim,
42+
max_size=arr.ndim, unique=True).map(tuple))
43+
original = xr.Variable(names, arr)
44+
coder = xr.coding.variables.CFScaleOffsetCoder()
45+
roundtripped = coder.decode(coder.encode(original))
46+
xr.testing.assert_identical(original, roundtripped)

properties/test_plotting.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""
2+
Property-based tests for plotting methods.
3+
4+
Note that Hypothesis can find a 2x2 array that causes an internal error
5+
for *every plot method tested*. Most are inside matplotlib. Good luck.
6+
7+
"""
8+
from __future__ import absolute_import, division, print_function
9+
10+
import pytest
11+
12+
from hypothesis import given, settings
13+
import hypothesis.strategies as st
14+
import hypothesis.extra.numpy as npst
15+
16+
import xarray as xr
17+
18+
# Run for a while - arrays are a bigger search space than usual
19+
settings.deadline = None
20+
21+
22+
two_dimensional_array = npst.arrays(
23+
dtype=st.one_of(
24+
npst.unsigned_integer_dtypes(),
25+
npst.integer_dtypes(),
26+
npst.floating_dtypes(),
27+
),
28+
shape=npst.array_shapes(min_dims=2, max_dims=2, min_side=2, max_side=4),
29+
)
30+
31+
32+
@pytest.mark.xfail
33+
@given(two_dimensional_array)
34+
def test_imshow(arr):
35+
xr.DataArray(arr).plot.imshow()
36+
37+
38+
@pytest.mark.xfail
39+
@given(two_dimensional_array)
40+
def test_pcolormesh(arr):
41+
xr.DataArray(arr).plot.pcolormesh()
42+
43+
44+
@pytest.mark.xfail
45+
@given(two_dimensional_array)
46+
def test_contour(arr):
47+
xr.DataArray(arr).plot.contour()
48+
49+
50+
@pytest.mark.xfail
51+
@given(two_dimensional_array)
52+
def test_contourf(arr):
53+
xr.DataArray(arr).plot.contourf()

0 commit comments

Comments
 (0)