Running Tests
Overview
Testing is an essential part of maintaining daolite (Durham Adaptive Optics Latency Inspection and Timing Estimator) and ensuring that all components work correctly. This guide explains how to run the test suite, generate coverage reports, and contribute new tests to the project.
Prerequisites
To run the daolite tests, you’ll need pytest and several testing-related packages:
pip install pytest pytest-cov pytest-xdist pytest-benchmark
Running the Test Suite
To run the complete test suite:
# Navigate to the project root directory
cd /path/to/daolite
# Run all tests
pytest
This will discover and run all tests in the tests/ directory.
Running Specific Tests
To run a specific test file or test function:
# Run tests in a specific file
pytest tests/test_camera.py
# Run a specific test function
pytest tests/test_camera.py::test_global_shutter_readout
# Run tests matching a pattern
pytest -k "camera or centroider"
Generating Coverage Reports
To generate a test coverage report:
# Run tests with coverage
pytest --cov=daolite
# Generate an HTML report
pytest --cov=daolite --cov-report=html
# Open the HTML report
open htmlcov/index.html
Parallel Test Execution
For faster test execution on multi-core systems:
# Run tests in parallel using available CPU cores
pytest -xvs -n auto
Benchmarking Tests
To benchmark performance-critical code:
# Run benchmark tests
pytest tests/test_centroider.py --benchmark-only
# Compare against previous benchmark results
pytest-benchmark compare --group-by=name
Running Tests with Different Python Versions
For testing compatibility with multiple Python versions:
# Using tox (first install with: pip install tox)
tox
This requires a configured tox.ini file in the project root.
Continuous Integration
The daolite project uses GitHub Actions for continuous integration testing. When a pull request is submitted, the test suite automatically runs on:
Different operating systems (Linux, macOS, Windows)
Different Python versions (3.8, 3.9, 3.10, 3.11)
Different configurations (with/without GPU support)
Adding New Tests
When adding new functionality to daolite, you should also add corresponding tests:
Create test functions in an appropriate file in the tests/ directory
Use the pytest framework for assertions and fixtures
Follow the naming convention test_*.py for test files and test_* for test functions
Include tests for both normal operation and edge cases
Example test function:
# tests/test_new_feature.py
import pytest
import numpy as np
from daolite.your_module import your_function
def test_your_function_basic():
"""Test basic functionality of your_function."""
result = your_function(param1=10, param2=20)
assert result.shape == (10, 2)
assert np.isclose(result.mean(), 15.0, rtol=1e-5)
def test_your_function_edge_case():
"""Test your_function with edge case inputs."""
with pytest.raises(ValueError):
your_function(param1=-1, param2=20) # Should raise ValueError for negative param1
Test Fixtures
daolite tests use pytest fixtures for setup and teardown of test resources:
# tests/conftest.py (shared fixtures)
import pytest
import numpy as np
from daolite import amd_epyc_7763
@pytest.fixture
def cpu_resource():
"""Return a CPU compute resource for testing."""
return amd_epyc_7763()
@pytest.fixture
def sample_data():
"""Generate sample data for testing."""
return np.random.rand(100, 100)
# In your test file
def test_with_fixtures(cpu_resource, sample_data):
"""Test using the fixtures."""
result = your_function(cpu_resource, sample_data)
assert result is not None
Mocking External Dependencies
For testing components that depend on external systems:
import pytest
from unittest.mock import MagicMock, patch
@patch('daolite.external_module.external_function')
def test_with_mock(mock_external):
"""Test with mocked external dependency."""
# Configure the mock
mock_external.return_value = 42
# Test your function that calls the external dependency
from daolite.your_module import function_that_uses_external
result = function_that_uses_external()
# Assert the result and that the mock was called
assert result == 42
mock_external.assert_called_once()
Property-Based Testing
For more thorough testing with varied inputs:
# Install hypothesis
pip install hypothesis
from hypothesis import given, strategies as st
@given(data=st.lists(st.floats(min_value=0, max_value=1000), min_size=10, max_size=100))
def test_property_based(data):
"""Test function with many random inputs."""
result = your_function(data)
# Assert properties that should hold for any valid input
assert len(result) == len(data)
assert all(r >= 0 for r in result)
Test Documentation
All tests should include clear docstrings explaining:
What functionality is being tested
What inputs are being used
What the expected outcome is
Example:
def test_center_of_gravity():
"""
Test the center_of_gravity function.
This test verifies that:
1. The function returns an array of the expected shape
2. Centroids are calculated correctly for a known input
3. The function handles edge cases appropriately
"""
# Test code here...
Troubleshooting Tests
Common issues and their solutions:
Tests not discovered: Ensure test files and functions follow the naming convention (test_*.py and test_*)
Import errors: Check that the package is installed in development mode (pip install -e .)
Failing assertions: Use pytest’s verbose mode (pytest -v) to see detailed output
Hanging tests: Use pytest’s timeout plugin (pip install pytest-timeout and pytest –timeout=30)
Segmentation faults: These often indicate memory errors in C extensions
Getting Support
If you need help with running tests or adding new tests, please:
Check the existing test files for examples
Review pytest documentation at https://docs.pytest.org/
Ask for help in the daolite GitHub repository by opening an issue
Contributing Tests
Contributions of new tests are welcome! Please follow these guidelines:
Ensure your tests are well-documented with clear assertions
Include both basic functionality tests and edge cases
Keep tests focused and small (test one thing per test function)
Follow the existing coding style
Include your tests in a pull request with the code they’re testing