Skip to content

Testing

Running tests

# All tests
pytest

# Verbose with coverage
pytest -v --cov=birdnet_stm32

# Skip slow/integration tests
pytest -m "not slow and not integration"

# Single file
pytest tests/test_audio_io.py

Test structure

tests/
├── conftest.py                  # Shared fixtures
├── fixtures/                    # Static test data
├── test_activity.py             # Activity detection logic
├── test_audio_io.py             # Audio loading, resampling, chunking
├── test_augmentation.py         # Audio augmentation pipeline
├── test_cli_defaults.py         # CLI default settings
├── test_config.py               # ModelConfig serialization
├── test_conversion.py           # TFLite conversion pipeline
├── test_data_pipeline.py        # Frontend-aware generator and calibration data
├── test_dataset.py              # File discovery, class handling
├── test_deploy_config.py        # Deployment configuration and firmware headers
├── test_dscnn.py                # DS-CNN model building and scaling
├── test_eval_reports.py         # Evaluation reporting (species AP, DET, HTML, benchmark)
├── test_frontend_layer.py       # AudioFrontendLayer shapes and modes
├── test_frontend_parity.py      # Float/quantized frontend parity
├── test_magnitude.py            # Magnitude scaling modes (pwl, none)
├── test_metrics.py              # ROC-AUC, cmAP, F1 computation
├── test_operational.py          # Device-facing INT8 release gate
├── test_optimizer.py            # Optimizer configuration
├── test_pooling.py              # avg/max/lme pooling
├── test_qat.py                  # Quantization-aware training
├── test_quantization_sim.py     # Quantization simulation utilities
├── test_runners.py              # Evaluation runner pipeline
├── test_spec_augment.py         # SpecAugment / frequency masking
├── test_split.py                # Backbone/classifier split and chained inference
├── test_spectrogram.py          # Spectrogram computation, shapes
├── test_threshold_opt.py        # Threshold optimization
├── test_train_memory_guard.py   # Host memory guard during training
└── test_train_to_eval.py        # End-to-end train → evaluate integration

Writing tests

Conventions

  • File naming: test_<module>.py mirroring the source module.
  • Function naming: test_<function>_<scenario>, e.g., test_load_audio_file_mono.
  • Fixtures: use conftest.py fixtures for shared setup (tmp dirs, sample audio, configs).
  • Markers: use @pytest.mark.slow for tests > 5 seconds, @pytest.mark.integration for end-to-end tests.

Fixtures from conftest.py

Fixture Description
sample_rate Default sample rate (22050 Hz)
chunk_duration Default chunk duration (3 seconds)
mel_bins Default number of mel bins (64)
spec_width Default spectrogram width in frames (256)
fft_length Default FFT length (512)
num_classes Default number of classes (10)
sine_wave 1 kHz sine wave (float32 array)
silence All-zeros signal
white_noise Random white noise (seeded)
tmp_dataset Temp directory with class_a/class_b WAV files

TensorFlow-dependent tests

Some tests require TensorFlow, which may not be available in all environments. Use pytest.importorskip:

tf = pytest.importorskip("tensorflow")

This skips the test gracefully if TF is not installed rather than failing.

Adding a new test

  1. Create tests/test_<module>.py.
  2. Import the module under test.
  3. Use fixtures from conftest.py where applicable.
  4. Add appropriate markers (@pytest.mark.slow, etc.).
  5. Run: pytest tests/test_<module>.py -v