NumPy uses pytest as its testing framework. Every module and package should have thorough unit tests that exercise full functionality and handle edge cases.
# Run all testsspin test -v# Run specific modulespin test numpy/random# Run specific filespin test -t numpy/core/tests/test_multiarray.py# Run specific testspin test -t numpy/core/tests/test_multiarray.py::test_array_empty_like# Run tests in parallelspin test -p auto
The first spin test run will build NumPy if needed. Subsequent runs are faster.
import numpy as np# Run all testsnp.test()# Run with verbose outputnp.test(verbose=2)# Include slow testsnp.test(label='full')# Test specific modulenp.random.test()
# Modern pytest style (preferred)with pytest.warns(DeprecationWarning, match="deprecated"): result = np.old_function()# Legacy style (avoid for new tests)from numpy.testing import assert_warnsassert_warns(DeprecationWarning, np.old_function)
import hypothesisfrom hypothesis import givenfrom hypothesis import strategies as stfrom hypothesis.extra import numpy as npst@given(arr=npst.arrays(dtype=np.float64, shape=st.integers(1, 100)))def test_sum_properties(arr): """Test properties that should hold for any input.""" result = np.sum(arr) # Sum should be finite for finite inputs if np.all(np.isfinite(arr)): assert np.isfinite(result) # Sum of positive numbers is positive if np.all(arr >= 0): assert result >= 0
class TestWithSetup: def setup_method(self): """Called before each test method.""" self.data = np.random.RandomState(42).random(100) self.temp_file = tempfile.mktemp() def teardown_method(self): """Called after each test method.""" if os.path.exists(self.temp_file): os.remove(self.temp_file) def test_something(self): """Test using setup data.""" result = np.myfunction(self.data) assert len(result) == 100
For thread-safe tests, call setup/teardown explicitly instead of using fixtures. See thread safety section.
@pytest.mark.slowdef test_expensive_operation(): """This test takes a long time.""" large_array = np.random.random((10000, 10000)) result = np.linalg.svd(large_array)
Run slow tests:
# Skip slow tests (default)spin test# Include slow testsspin test -m full
NumPy CI uses pytest-run-parallel to test thread safety:
# Run tests in parallel threadsspin test -p auto# Run with specific thread countspin test -p 4# Skip thread-unsafe testsspin test -p auto -- --skip-thread-unsafe=true
class TestThreadSafe: def test_with_explicit_setup(self): """Thread-safe test.""" # Create fresh state for each test rng = np.random.RandomState(42) data = rng.random(100) result = np.myfunction(data) assert result.shape == (100,)
Don’t:
# Not thread-safe - uses class-level fixtureclass TestNotThreadSafe: @pytest.fixture(autouse=True) def setup(self): self.data = np.random.random(100) def test_something(self): # Multiple threads could access self.data simultaneously result = np.myfunction(self.data)
def add(a, b): """ Add two numbers. Examples -------- >>> add(1, 2) 3 >>> add(-1, 1) 0 """ return a + b
Run doctests:
# Install scipy-doctestpip install scipy-doctest# Run all doctestsspin check-docs -v# Run for specific modulespin check-docs numpy/linalg# Run with pattern matchingspin check-docs -- -k 'det and not slogdet'
Doctests run in a clean environment with import numpy as np already executed.
import timeitdef test_performance(): """Test that operation meets performance target.""" setup = "import numpy as np; a = np.random.random((1000, 1000))" time = timeit.timeit("np.sum(a)", setup=setup, number=100) # Should complete in less than 1 second for 100 iterations assert time < 1.0