Unit Tests¶
127 tests across 11 files. No hardware needed — mocked data only.
Run the suite¶
cd wearable_har_v2
.venv/bin/python -m pytest tests/ -v
# Quick pass/fail summary
.venv/bin/python -m pytest tests/ -q
Test files¶
| File | Tests | Covers |
|---|---|---|
test_protocol.py |
22 | CRC32, sizes, offsets, magic, seq wrap, labels, feature-dim invariants |
test_serial_reader.py |
16 | Parse valid/invalid frames, resync, false-magic rejection, IMUData, SensorFrame |
test_imu_driver.py |
8 | Quat/linacc scaling, I²C address map, 28-byte payload layout |
test_uart_protocol.py |
14 | 70-byte frame, CRC, IMU4/5 offsets, bandwidth |
test_analog.py |
8 | ADC scaling, FSR divider, pin map |
test_feature_extraction.py |
19 | Window config, quat→euler, stats, ZCR, streaming, 328-dim |
test_data_recorder.py |
5 | HDF5 write/read round-trip, metadata, chunk flush |
test_live_inference.py |
6 | Model load, predict, top-k, EMA, reset |
test_train_model.py |
9 | Synthetic data, dataset, model shapes, LOSO folds, export |
test_integration.py |
6 | Packet→frame→features pipeline, stick-figure math |
test_sensor_subsets.py |
14 | Modular bring-up: one sensor → several → another type → combos |
| Total | 127 |
Running individual tests¶
# Single test file
.venv/bin/python -m pytest tests/test_protocol.py -v
# Single test function
.venv/bin/python -m pytest tests/test_protocol.py::test_crc32_known_vector -v
# Tests matching a keyword
.venv/bin/python -m pytest tests/ -k "crc"
Per-sensor isolation tests¶
The bring-up test (test_sensor_subsets.py) allows testing one sensor type at a time:
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k IMUOnly # 1 IMU, then 2 IMUs
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k EMGOnly
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k FSROnly
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k TwoTypes # IMU+EMG, IMU+FSR, EMG+FSR
.venv/bin/python -m pytest tests/test_sensor_subsets.py -k AllSensors
Each class runs against the feature extractor with the other channels zeroed — exactly what the firmware emits when a sensor is absent, disconnected, or failing. This means you can validate each sensor type in isolation before combining them.
Interpreting failures¶
| Failure type | Example | Fix |
|---|---|---|
| Magic validation | assert pktsize == 214 fails |
protocol.py and packet_protocol.h are out of sync |
| CRC mismatch | crc_calc != expected |
CRC polynomial or byte-range changed |
| Feature dim | assert feats.shape == (328,) fails |
FeatureExtractor or protocol.py changed, dims no longer match |
| Model shapes | output.shape != (batch, 11) |
Model arch or NUM_CLASSES changed |
| Sensor subset | AssertionError in test_IMUOnly |
Feature extractor fails when EMG/FSR are zeroed |
All tests use deterministic seeded random data — no flaky tests. If a test fails, something in the code genuinely changed.
Adding tests¶
Tests live under tests/ mirroring the host/ module structure. Use pytest
fixtures for mock data. Each test file imports only the module under test:
# test_protocol.py
from host.protocol import crc32, ACTIVITY_LABELS, PKT_STM32_SIZE
def test_crc32_known_vector():
assert crc32(b'123456789') == 0xCBF43926
def test_label_count():
assert len(ACTIVITY_LABELS) == 11
No hardware imports, no serial port, no file system — tests must pass in CI without any connected devices.