Testing
This document describes the testing strategy and procedures for MouseMaster.
Testing Overview
MouseMaster uses a hybrid testing approach:
Test Type |
Tool |
Environment |
When to Run |
|---|---|---|---|
Unit Tests |
pytest |
Any Python 3.9+ |
On every commit, in CI |
Integration Tests |
Slicer Test Framework |
3D Slicer |
Before release |
Manual Tests |
Human |
3D Slicer |
Before release |
Unit Tests
Running Unit Tests
# Run all unit tests
uv run pytest MouseMaster/Testing/Python/ -v
# Run with coverage
uv run pytest MouseMaster/Testing/Python/ -v --cov=MouseMaster/MouseMasterLib
# Run specific test file
uv run pytest MouseMaster/Testing/Python/test_mouse_profile.py -v
# Run specific test
uv run pytest MouseMaster/Testing/Python/test_mouse_profile.py::TestMouseProfile::test_from_dict -v
What Unit Tests Cover
test_mouse_profile.py: MouseButton, MouseFeatures, MouseProfile classestest_preset_manager.py: Mapping, Preset, PresetManager classestest_platform_adapter.py: PlatformAdapter and platform-specific adapterstest_button_detector.py: ButtonDetector and detection session
Adding New Unit Tests
Create test file in
MouseMaster/Testing/Python/test_*.pyImport from
MouseMasterLibUse fixtures from
conftest.pyFollow naming:
test_<what_is_tested>
Example:
import pytest
from MouseMasterLib.MouseProfile import MouseProfile
class TestMouseProfile:
def test_from_dict_valid(self, sample_mouse_dict):
profile = MouseProfile.from_dict(sample_mouse_dict)
assert profile.id == sample_mouse_dict["id"]
assert len(profile.buttons) == len(sample_mouse_dict["buttons"])
def test_from_dict_missing_required(self):
with pytest.raises(KeyError):
MouseProfile.from_dict({})
Integration Tests
Running in Slicer
# In Slicer Python console
import MouseMaster
test = MouseMaster.MouseMasterTest()
test.runTest()
What Integration Tests Cover
Module loading and initialization
Event handler installation
UI widget creation
Settings persistence
Manual Test Procedures
MT-002: Preset Save/Load
Purpose: Verify presets persist across sessions
Steps:
Create a new preset with custom mappings
Save the preset
Close and reopen 3D Slicer
Open MouseMaster module
Select the saved preset
Pass Criteria: All mappings match original configuration
MT-003: Context-Sensitive Bindings
Purpose: Verify different bindings in different modules
Steps:
Create preset with:
Default: Back -> Undo
SegmentEditor: Back -> Previous Segment
Save preset
Open Welcome module, press Back
Verify Undo triggered
Open Segment Editor, create segmentation
Press Back
Verify segment selection changed
Pass Criteria: Correct action in each module
MT-004: Device Hot-Plug
Purpose: Verify behavior when mouse is disconnected/reconnected
Steps:
Activate MouseMaster with preset
Disconnect mouse USB
Wait 5 seconds
Reconnect mouse
Test button mapping
Pass Criteria: No crashes, mappings restored
MT-005: Cross-Platform Verification
Purpose: Verify functionality on all platforms
Steps (repeat on each platform):
Install extension
Load module
Run MT-001 basic mapping test
Run MT-002 preset save/load test
Check Slicer console for errors
Pass Criteria: No platform-specific failures
MT-007: Preset Export/Import
Purpose: Verify preset sharing functionality
Steps:
Select preset
Click “Export…”
Save to file
Delete the preset (or use different Slicer install)
Click “Import…”
Select the exported file
Verify preset imported correctly
Pass Criteria: Imported preset matches original
MT-008: Error Handling
Purpose: Verify graceful error handling
Steps:
Try to load corrupt preset JSON
Try to import nonexistent file
Try to save preset without mouse selected
Check Slicer console for error messages
Pass Criteria: Errors logged, UI remains responsive
Test Matrix
Feature |
Unit |
Integration |
Manual |
|---|---|---|---|
MouseProfile parsing |
X |
||
Preset serialization |
X |
||
Platform adaptation |
X |
||
Button detection |
X |
MT-006 |
|
Event handling |
X |
MT-001 |
|
UI functionality |
X |
MT-001-008 |
|
Persistence |
X |
MT-002 |
|
Context bindings |
MT-003 |
||
Cross-platform |
MT-005 |
CI/CD Pipeline
The GitHub Actions workflow runs:
jobs:
lint:
- ruff check .
- ruff format --check .
- mypy MouseMaster/MouseMasterLib/
test:
- pytest MouseMaster/Testing/Python/ -v
Reporting Issues
When reporting test failures:
Note which test failed (ID if manual)
Include Slicer version
Include OS and version
Attach Slicer console output
Attach MouseMaster log if available