Mark some tests as slow for quicker feedback

This commit is contained in:
mbsantiago 2026-03-29 15:55:24 +01:00
parent c24056214c
commit e80fe8675d
12 changed files with 42 additions and 1 deletions

View File

@ -20,7 +20,15 @@ install:
# Testing & Coverage # Testing & Coverage
# Run tests using pytest. # Run tests using pytest.
test: test:
uv run pytest -n auto {{TESTS_DIR}} uv run pytest {{TESTS_DIR}}
# Run the fast subset of tests (excludes @pytest.mark.slow).
test-quick:
uv run pytest --durations=10 -m "not slow" {{TESTS_DIR}}
# Run only long-running tests marked with @pytest.mark.slow.
test-slow:
uv run pytest -m "slow" {{TESTS_DIR}}
# Run tests and generate coverage data. # Run tests and generate coverage data.
coverage: coverage:

View File

@ -129,3 +129,8 @@ exclude = [
"src/batdetect2/finetune", "src/batdetect2/finetune",
"src/batdetect2/utils", "src/batdetect2/utils",
] ]
[tool.pytest.ini_options]
markers = [
"slow: marks long-running tests that are skipped in quick runs",
]

View File

@ -46,6 +46,7 @@ def test_process_file_returns_recording_level_predictions(
) )
@pytest.mark.slow
def test_process_files_is_batch_size_invariant( def test_process_files_is_batch_size_invariant(
api_v2: BatDetect2API, api_v2: BatDetect2API,
example_audio_files: list[Path], example_audio_files: list[Path],
@ -180,6 +181,7 @@ def test_user_can_read_extracted_features_per_detection(
assert all(vec.size > 0 for vec in feature_vectors) assert all(vec.size > 0 for vec in feature_vectors)
@pytest.mark.slow
def test_user_can_load_checkpoint_and_finetune( def test_user_can_load_checkpoint_and_finetune(
tmp_path: Path, tmp_path: Path,
example_annotations, example_annotations,
@ -293,6 +295,7 @@ def test_checkpoint_with_same_targets_config_keeps_heads_unchanged(
) )
@pytest.mark.slow
def test_user_can_finetune_only_heads( def test_user_can_finetune_only_heads(
tmp_path: Path, tmp_path: Path,
example_annotations, example_annotations,
@ -328,6 +331,7 @@ def test_user_can_finetune_only_heads(
assert list(finetune_dir.rglob("*.ckpt")) assert list(finetune_dir.rglob("*.ckpt"))
@pytest.mark.slow
def test_user_can_evaluate_small_dataset_and_get_metrics( def test_user_can_evaluate_small_dataset_and_get_metrics(
api_v2: BatDetect2API, api_v2: BatDetect2API,
example_annotations, example_annotations,
@ -414,6 +418,7 @@ def test_detection_threshold_override_changes_process_file_results(
) )
@pytest.mark.slow
def test_detection_threshold_override_is_ephemeral_in_process_file( def test_detection_threshold_override_is_ephemeral_in_process_file(
api_v2: BatDetect2API, api_v2: BatDetect2API,
example_audio_files: list[Path], example_audio_files: list[Path],

View File

@ -1,4 +1,5 @@
import numpy as np import numpy as np
import pytest
import torch import torch
import torch.nn.functional as F import torch.nn.functional as F
from hypothesis import given, settings from hypothesis import given, settings
@ -10,6 +11,7 @@ from batdetect2.utils import audio_utils, detector_utils
@given(duration=st.floats(min_value=0.1, max_value=1)) @given(duration=st.floats(min_value=0.1, max_value=1))
@settings(deadline=None) @settings(deadline=None)
@pytest.mark.slow
def test_can_compute_correct_spectrogram_width(duration: float): def test_can_compute_correct_spectrogram_width(duration: float):
samplerate = parameters.TARGET_SAMPLERATE_HZ samplerate = parameters.TARGET_SAMPLERATE_HZ
params = parameters.DEFAULT_SPECTROGRAM_PARAMETERS params = parameters.DEFAULT_SPECTROGRAM_PARAMETERS
@ -89,6 +91,7 @@ def test_pad_audio_without_fixed_size(duration: float):
@given(duration=st.floats(min_value=0.1, max_value=2)) @given(duration=st.floats(min_value=0.1, max_value=2))
@settings(deadline=None) @settings(deadline=None)
@pytest.mark.slow
def test_computed_spectrograms_are_actually_divisible_by_the_spec_divide_factor( def test_computed_spectrograms_are_actually_divisible_by_the_spec_divide_factor(
duration: float, duration: float,
): ):

View File

@ -3,11 +3,13 @@
from pathlib import Path from pathlib import Path
import pandas as pd import pandas as pd
import pytest
from click.testing import CliRunner from click.testing import CliRunner
from batdetect2.cli import cli from batdetect2.cli import cli
@pytest.mark.slow
def test_cli_detect_command_on_test_audio(tmp_path: Path) -> None: def test_cli_detect_command_on_test_audio(tmp_path: Path) -> None:
"""User story: run legacy detect on example audio directory.""" """User story: run legacy detect on example audio directory."""
@ -29,6 +31,7 @@ def test_cli_detect_command_on_test_audio(tmp_path: Path) -> None:
assert len(list(results_dir.glob("*.json"))) == 3 assert len(list(results_dir.glob("*.json"))) == 3
@pytest.mark.slow
def test_cli_detect_command_with_non_trivial_time_expansion( def test_cli_detect_command_with_non_trivial_time_expansion(
tmp_path: Path, tmp_path: Path,
) -> None: ) -> None:
@ -52,6 +55,7 @@ def test_cli_detect_command_with_non_trivial_time_expansion(
assert "Time Expansion Factor: 10" in result.stdout assert "Time Expansion Factor: 10" in result.stdout
@pytest.mark.slow
def test_cli_detect_command_with_spec_feature_flag(tmp_path: Path) -> None: def test_cli_detect_command_with_spec_feature_flag(tmp_path: Path) -> None:
"""User story: request extra spectral features in output CSV.""" """User story: request extra spectral features in output CSV."""

View File

@ -20,6 +20,7 @@ def test_cli_predict_help() -> None:
assert "dataset" in result.output assert "dataset" in result.output
@pytest.mark.slow
def test_cli_predict_directory_runs_on_real_audio( def test_cli_predict_directory_runs_on_real_audio(
tmp_path: Path, tmp_path: Path,
tiny_checkpoint_path: Path, tiny_checkpoint_path: Path,

View File

@ -2,6 +2,7 @@
from pathlib import Path from pathlib import Path
import pytest
from click.testing import CliRunner from click.testing import CliRunner
from batdetect2.cli import cli from batdetect2.cli import cli
@ -19,6 +20,7 @@ def test_cli_train_help() -> None:
assert "--model" in result.output assert "--model" in result.output
@pytest.mark.slow
def test_cli_train_from_checkpoint_runs_on_small_dataset( def test_cli_train_from_checkpoint_runs_on_small_dataset(
tmp_path: Path, tmp_path: Path,
tiny_checkpoint_path: Path, tiny_checkpoint_path: Path,

View File

@ -2,11 +2,13 @@
from pathlib import Path from pathlib import Path
import pytest
from click.testing import CliRunner from click.testing import CliRunner
from batdetect2.cli import cli from batdetect2.cli import cli
runner = CliRunner() runner = CliRunner()
pytestmark = pytest.mark.slow
def test_can_process_jeff37_files( def test_can_process_jeff37_files(

View File

@ -2,11 +2,14 @@
import os import os
import pytest
from batdetect2 import api from batdetect2 import api
DATA_DIR = os.path.join(os.path.dirname(__file__), "data") DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
@pytest.mark.slow
def test_no_detections_above_nyquist(): def test_no_detections_above_nyquist():
"""Test that no detections are made above the nyquist frequency.""" """Test that no detections are made above the nyquist frequency."""
# Recording donated by @@kdarras # Recording donated by @@kdarras

View File

@ -4,6 +4,7 @@ from pathlib import Path
from typing import List from typing import List
import numpy as np import numpy as np
import pytest
from hypothesis import given, settings from hypothesis import given, settings
from hypothesis import strategies as st from hypothesis import strategies as st
@ -13,6 +14,7 @@ from batdetect2.detector import parameters
@settings(deadline=None, max_examples=5) @settings(deadline=None, max_examples=5)
@given(duration=st.floats(min_value=0.1, max_value=2)) @given(duration=st.floats(min_value=0.1, max_value=2))
@pytest.mark.slow
def test_can_import_model_without_pickle(duration: float): def test_can_import_model_without_pickle(duration: float):
# NOTE: remove this test once no other issues are found This is a temporary # NOTE: remove this test once no other issues are found This is a temporary
# test to check that change in model loading did not impact model behaviour # test to check that change in model loading did not impact model behaviour
@ -42,6 +44,7 @@ def test_can_import_model_without_pickle(duration: float):
assert predictions_without_pickle == predictions_with_pickle assert predictions_without_pickle == predictions_with_pickle
@pytest.mark.slow
def test_can_import_model_without_pickle_on_test_data( def test_can_import_model_without_pickle_on_test_data(
example_audio_files: List[Path], example_audio_files: List[Path],
): ):

View File

@ -1,10 +1,13 @@
from pathlib import Path from pathlib import Path
import pytest
from soundevent import data from soundevent import data
from batdetect2.config import BatDetect2Config from batdetect2.config import BatDetect2Config
from batdetect2.train import run_train from batdetect2.train import run_train
pytestmark = pytest.mark.slow
def _build_fast_train_config() -> BatDetect2Config: def _build_fast_train_config() -> BatDetect2Config:
config = BatDetect2Config() config = BatDetect2Config()

View File

@ -37,6 +37,7 @@ def test_can_initialize_default_module():
assert isinstance(module, L.LightningModule) assert isinstance(module, L.LightningModule)
@pytest.mark.slow
def test_can_save_checkpoint( def test_can_save_checkpoint(
tmp_path: Path, tmp_path: Path,
clip: data.Clip, clip: data.Clip,
@ -182,6 +183,7 @@ def test_api_from_checkpoint_reconstructs_model_config(tmp_path: Path):
assert api.audio_config.samplerate == module.model_config.samplerate assert api.audio_config.samplerate == module.model_config.samplerate
@pytest.mark.slow
def test_train_smoke_produces_loadable_checkpoint( def test_train_smoke_produces_loadable_checkpoint(
tmp_path: Path, tmp_path: Path,
example_annotations: list[data.ClipAnnotation], example_annotations: list[data.ClipAnnotation],