|
@@ -0,0 +1,190 @@
|
|
|
|
|
+# Testing Guide
|
|
|
|
|
+
|
|
|
|
|
+This document explains how to run tests for the Dune Weaver backend.
|
|
|
|
|
+
|
|
|
|
|
+## Quick Start
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Install test dependencies
|
|
|
|
|
+pip install -r requirements-dev.txt
|
|
|
|
|
+
|
|
|
|
|
+# Run all unit tests (no hardware needed)
|
|
|
|
|
+pytest tests/unit/ -v
|
|
|
|
|
+
|
|
|
|
|
+# Run with coverage report
|
|
|
|
|
+pytest tests/ --cov=modules --cov-report=term-missing
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Test Structure
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+tests/
|
|
|
|
|
+├── conftest.py # Shared fixtures
|
|
|
|
|
+├── unit/ # Unit tests (run in CI, no hardware)
|
|
|
|
|
+│ ├── conftest.py
|
|
|
|
|
+│ ├── test_api_patterns.py
|
|
|
|
|
+│ ├── test_api_playlists.py
|
|
|
|
|
+│ ├── test_api_status.py
|
|
|
|
|
+│ ├── test_connection_manager.py
|
|
|
|
|
+│ ├── test_pattern_manager.py
|
|
|
|
|
+│ └── test_playlist_manager.py
|
|
|
|
|
+├── integration/ # Integration tests (require hardware)
|
|
|
|
|
+│ ├── conftest.py
|
|
|
|
|
+│ ├── test_hardware.py
|
|
|
|
|
+│ ├── test_playback_controls.py
|
|
|
|
|
+│ └── test_playlist.py
|
|
|
|
|
+└── fixtures/ # Test data files
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Unit Tests
|
|
|
|
|
+
|
|
|
|
|
+Unit tests mock all hardware dependencies and run quickly. They're safe to run anywhere.
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Run all unit tests
|
|
|
|
|
+pytest tests/unit/ -v
|
|
|
|
|
+
|
|
|
|
|
+# Run specific test file
|
|
|
|
|
+pytest tests/unit/test_pattern_manager.py -v
|
|
|
|
|
+
|
|
|
|
|
+# Run specific test
|
|
|
|
|
+pytest tests/unit/test_api_status.py::test_get_status -v
|
|
|
|
|
+
|
|
|
|
|
+# Run tests matching a pattern
|
|
|
|
|
+pytest tests/unit/ -v -k "playlist"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Integration Tests
|
|
|
|
|
+
|
|
|
|
|
+Integration tests require the sand table hardware to be connected. They are **skipped by default**.
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Run integration tests (with hardware connected)
|
|
|
|
|
+pytest tests/integration/ --run-hardware -v
|
|
|
|
|
+
|
|
|
|
|
+# Run specific integration test file
|
|
|
|
|
+pytest tests/integration/test_playback_controls.py --run-hardware -v
|
|
|
|
|
+
|
|
|
|
|
+# Run with output visible (helpful for debugging)
|
|
|
|
|
+pytest tests/integration/ --run-hardware -v -s
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Integration Test Categories
|
|
|
|
|
+
|
|
|
|
|
+| File | What it tests | Duration |
|
|
|
|
|
+|------|---------------|----------|
|
|
|
|
|
+| `test_hardware.py` | Serial connection, homing, movement, pattern execution | ~5-10 min |
|
|
|
|
|
+| `test_playback_controls.py` | Pause, resume, stop, skip, speed control | ~5 min |
|
|
|
|
|
+| `test_playlist.py` | Playlist modes, clear patterns, state updates | ~5 min |
|
|
|
|
|
+
|
|
|
|
|
+### Safety Notes
|
|
|
|
|
+
|
|
|
|
|
+- **Movement tests physically move the table** — ensure the ball path is clear
|
|
|
|
|
+- **Homing tests run the homing sequence** — table will move to home position
|
|
|
|
|
+- **Pattern tests execute real patterns** — star.thr runs end-to-end
|
|
|
|
|
+
|
|
|
|
|
+## Coverage Reports
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Terminal report
|
|
|
|
|
+pytest tests/ --cov=modules --cov-report=term-missing
|
|
|
|
|
+
|
|
|
|
|
+# HTML report (creates htmlcov/ directory)
|
|
|
|
|
+pytest tests/ --cov=modules --cov-report=html
|
|
|
|
|
+open htmlcov/index.html
|
|
|
|
|
+
|
|
|
|
|
+# XML report (for CI tools)
|
|
|
|
|
+pytest tests/ --cov=modules --cov-report=xml
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## CI Behavior
|
|
|
|
|
+
|
|
|
|
|
+When `CI=true` environment variable is set:
|
|
|
|
|
+- All `@pytest.mark.hardware` tests are automatically skipped
|
|
|
|
|
+- Unit tests run normally
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+# Simulate CI environment locally
|
|
|
|
|
+CI=true pytest tests/ -v
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Common Commands
|
|
|
|
|
+
|
|
|
|
|
+| Command | Description |
|
|
|
|
|
+|---------|-------------|
|
|
|
|
|
+| `pytest tests/unit/ -v` | Run unit tests |
|
|
|
|
|
+| `pytest tests/integration/ --run-hardware -v` | Run integration tests |
|
|
|
|
|
+| `pytest tests/ --cov=modules` | Run with coverage |
|
|
|
|
|
+| `pytest tests/ -v -k "pattern"` | Run tests matching "pattern" |
|
|
|
|
|
+| `pytest tests/ -x` | Stop on first failure |
|
|
|
|
|
+| `pytest tests/ --lf` | Run only last failed tests |
|
|
|
|
|
+| `pytest tests/ -v -s` | Show print statements |
|
|
|
|
|
+
|
|
|
|
|
+## Adding New Tests
|
|
|
|
|
+
|
|
|
|
|
+### Unit Test Example
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+# tests/unit/test_my_feature.py
|
|
|
|
|
+import pytest
|
|
|
|
|
+from unittest.mock import MagicMock, patch
|
|
|
|
|
+
|
|
|
|
|
+def test_my_function():
|
|
|
|
|
+ """Test description here."""
|
|
|
|
|
+ # Arrange
|
|
|
|
|
+ expected = "result"
|
|
|
|
|
+
|
|
|
|
|
+ # Act
|
|
|
|
|
+ result = my_function()
|
|
|
|
|
+
|
|
|
|
|
+ # Assert
|
|
|
|
|
+ assert result == expected
|
|
|
|
|
+
|
|
|
|
|
+@pytest.mark.asyncio
|
|
|
|
|
+async def test_async_function(async_client):
|
|
|
|
|
+ """Test async endpoint."""
|
|
|
|
|
+ response = await async_client.get("/my_endpoint")
|
|
|
|
|
+ assert response.status_code == 200
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Integration Test Example
|
|
|
|
|
+
|
|
|
|
|
+```python
|
|
|
|
|
+# tests/integration/test_my_hardware.py
|
|
|
|
|
+import pytest
|
|
|
|
|
+
|
|
|
|
|
+@pytest.mark.hardware
|
|
|
|
|
+@pytest.mark.slow
|
|
|
|
|
+def test_hardware_operation(hardware_port, run_hardware):
|
|
|
|
|
+ """Test that requires real hardware."""
|
|
|
|
|
+ if not run_hardware:
|
|
|
|
|
+ pytest.skip("Hardware tests disabled")
|
|
|
|
|
+
|
|
|
|
|
+ from modules.connection import connection_manager
|
|
|
|
|
+
|
|
|
|
|
+ conn = connection_manager.SerialConnection(hardware_port)
|
|
|
|
|
+ try:
|
|
|
|
|
+ assert conn.is_connected()
|
|
|
|
|
+ # ... test hardware operation
|
|
|
|
|
+ finally:
|
|
|
|
|
+ conn.close()
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## Troubleshooting
|
|
|
|
|
+
|
|
|
|
|
+### Tests hang or timeout
|
|
|
|
|
+- Check if hardware is connected and powered on
|
|
|
|
|
+- Verify serial port is not in use by another application
|
|
|
|
|
+- Try running with `-s` flag to see output
|
|
|
|
|
+
|
|
|
|
|
+### Import errors
|
|
|
|
|
+- Ensure you're in the project root directory
|
|
|
|
|
+- Install dependencies: `pip install -r requirements-dev.txt`
|
|
|
|
|
+
|
|
|
|
|
+### Hardware tests skip unexpectedly
|
|
|
|
|
+- Make sure to pass `--run-hardware` flag
|
|
|
|
|
+- Check that `CI` environment variable is not set
|
|
|
|
|
+
|
|
|
|
|
+### Coverage shows 0%
|
|
|
|
|
+- Ensure `relative_files = true` is in pyproject.toml
|
|
|
|
|
+- Run from project root directory
|