Files
info 66ecf55ea9 docs: OpenWiki-Dokumentation und Auto-Update-Workflow hinzufügen
Fügt generierte OpenWiki-Docs (Architektur, Domain, Betrieb, Tests, Workflows)
sowie den GitHub-Actions-Workflow zur automatischen Aktualisierung hinzu.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 14:53:30 +02:00

3.6 KiB

type, title, description, tags
type title description tags
TestingGuide Test-Leitfaden pytest-Setup für whisper-local. Plattformspezifische Tests via skipif, AsyncMock für asyncio-Callbacks, Mocking-Muster für sounddevice und faster-whisper.
testing
pytest
asyncio
mocking
platform-specific

Test-Leitfaden

Setup

uv run pytest              # alle Tests
uv run pytest -v           # verbose
uv run pytest tests/test_main.py  # einzelne Datei

Dev-Dependencies: pytest>=8.0.0, pytest-asyncio>=0.24.0 (in pyproject.toml unter [dependency-groups] dev).

Plattformspezifische Tests

Plattformabhängige Tests werden mit @pytest.mark.skipif übersprungen:

import sys
import pytest

@pytest.mark.skipif(sys.platform != "linux", reason="nur Linux")
def test_evdev_listener():
    ...

@pytest.mark.skipif(sys.platform != "win32", reason="nur Windows")
def test_pynput_listener():
    ...

Dieses Muster wird durchgehend angewendet — z.B. in test_hotkey.py (evdev vs. pynput), test_media_mpris.py (Linux), test_media_smtc.py (Windows).

Async-Tests

Async-Tests verwenden pytest-asyncio:

@pytest.mark.asyncio
async def test_on_press_starts_recording():
    app = App(config=Config())
    app.on_press = AsyncMock()
    await app.on_press()
    ...

Async-Callbacks (on_press, on_release, Mikrofon-Monitor-Callbacks) werden mit unittest.mock.AsyncMock gemockt.

Mocking-Muster

sounddevice

Recorder und PollMonitor verwenden sounddevice. In Tests wird sd.InputStream bzw. sd.query_devices gemockt:

@patch("whisper_local.recorder.sd.InputStream")
def test_recorder_start(mock_stream):
    recorder = Recorder()
    recorder.start()
    mock_stream.assert_called_once()

faster-whisper

Transcriber wird mit einem gemockten WhisperModel instanziiert, um Modell-Downloads zu vermeiden:

def test_transcriber(mock_model):
    transcriber = Transcriber(model=mock_model, language="de")
    ...

Der Transcriber akzeptiert ein optionales model-Argument, das in Tests genutzt wird — ein expliziter Design-Entscheidung (Commit 3a58099).

Windows COM / winrt

test_media_smtc.py sichert winrt-Imports plattformabsichern ab. test_main.py mockt create_monitor, um COM-Abhängigkeiten zu umgehen.

Test-Übersicht

Test-Datei Fokus Plattform
test_config.py Config laden/speichern, Defaults, TOML-Escaping alle
test_recorder.py Recorder start/stop, min_duration-Filter alle
test_transcriber.py Transcriber mit gemocktem Model alle
test_hotkey.py Beide Backends, Key-Repeat-Unterdrückung je skipif
test_inserter.py Wayland + Win32, Clipboard-Restaurierung je skipif
test_media_factory.py Factory-Dispatch alle
test_media_mpris.py MprisController, Circuit-Breaker Linux
test_media_smtc.py SmtcController, Circuit-Breaker Windows
test_microphone_monitor.py PollMonitor, Start-Check alle
test_tray.py Tray-App, AppState, Icon, Settings alle
test_download_progress.py Download-Dialog alle
test_main.py App-Integration: Zyklus, Config-Reload, Mikrofon alle

Wichtige Test-Konventionen

  • Mocks statt echter Hardware: Kein echtes Mikrofon, keine echte Tastatur, kein D-Bus, kein SMTC in Tests.
  • create_monitor mocken in test_main.py: Verhindert COM-Initialisierung auf Nicht-Windows-Plattformen (Commit 1f8adc5).
  • Recorder vor Ersatz stoppen: test_main.py stellt sicher, dass der Recorder gestoppt wird, bevor er durch Config-Reload ersetzt wird (Commit 1f8adc5).