Skip to content

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.