test: create new test architecture with shared property/API tests
- Add tests/common/ with parametrized property tests (positivity, shape, NaN, stability) - Add tests/physics/ with unique physics behavior tests for 6 correction components - Add tests/quality/ with API contract tests for 6 correction components - Add pytest markers in pyproject.toml: property, physics, api, quality, integration - New tests: 94 tests passing (physics + quality + common helpers) - Old tests in tests/ root still present — migration in progress - Total: 261 tests collected (230 old + 94 new - 63 duplicates removed) The shared helpers eliminate 18 duplicate test patterns across correction components. Each component now has: - tests/physics/test_<name>.py — unique physics behavior - tests/quality/test_api_<name>.py — API contract + shared property checks - tests/common/test_property_tests.py — shared helpers (imported, not duplicated)
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
Shared API contract tests for all SpectrumComponent subclasses.
|
||||
|
||||
These tests verify that every component adheres to the SpectrumComponent
|
||||
interface contract. They are parameterized to run against all component
|
||||
classes automatically.
|
||||
|
||||
## Contract requirements
|
||||
|
||||
1. `__call__(W) -> np.ndarray` — the component is callable with W array
|
||||
2. `__init__` accepts `logger: Optional[Logger] = None`
|
||||
3. `__repr__` returns a non-empty string
|
||||
4. Subclasses implement `__call__` (abstract method)
|
||||
|
||||
## Usage
|
||||
|
||||
Each component test file imports these helpers:
|
||||
|
||||
```python
|
||||
import pytest
|
||||
from beta_spectrum.components.fermi import FermiFunction
|
||||
from tests.common.test_api_tests import test_component_is_callable
|
||||
|
||||
class TestFermiAPI:
|
||||
@pytest.mark.api
|
||||
def test_callable(self):
|
||||
ff = FermiFunction(Z=20, A=40)
|
||||
test_component_is_callable(ff, "FermiFunction")
|
||||
```
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
def _test_component_is_callable(component, component_name="Component"):
|
||||
"""Component must be callable with array input."""
|
||||
assert callable(component), (
|
||||
f"{component_name}: component is not callable"
|
||||
)
|
||||
|
||||
W = np.array([1.5, 2.0, 3.0])
|
||||
result = component(W)
|
||||
|
||||
assert isinstance(result, np.ndarray), (
|
||||
f"{component_name}: __call__ returned {type(result)}, "
|
||||
f"expected np.ndarray"
|
||||
)
|
||||
assert result.shape == W.shape, (
|
||||
f"{component_name}: shape mismatch {W.shape} → {result.shape}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
def _test_component_repr(component, component_name="Component"):
|
||||
"""Component must have a non-empty repr."""
|
||||
repr_str = repr(component)
|
||||
assert isinstance(repr_str, str), (
|
||||
f"{component_name}: repr returned {type(repr_str)}"
|
||||
)
|
||||
assert len(repr_str) > 0, (
|
||||
f"{component_name}: repr is empty string"
|
||||
)
|
||||
# repr should contain the class name
|
||||
assert component_name in repr_str or component.__class__.__name__ in repr_str, (
|
||||
f"{component_name}: repr should contain class name. Got: {repr_str}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
def _test_component_list_input(component, component_name="Component"):
|
||||
"""Component must handle Python list input (numpy converts it)."""
|
||||
result = component([1.5, 2.0, 3.0])
|
||||
assert isinstance(result, np.ndarray), (
|
||||
f"{component_name}: list input returned {type(result)}"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.api
|
||||
def _test_component_empty_input(component, component_name="Component"):
|
||||
"""Component must handle empty array input gracefully."""
|
||||
result = component(np.array([]))
|
||||
assert isinstance(result, np.ndarray), (
|
||||
f"{component_name}: empty input returned {type(result)}"
|
||||
)
|
||||
assert result.shape == (0,), (
|
||||
f"{component_name}: empty input should return empty array"
|
||||
)
|
||||
Reference in New Issue
Block a user