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>
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. |
|
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_monitormocken intest_main.py: Verhindert COM-Initialisierung auf Nicht-Windows-Plattformen (Commit1f8adc5).- Recorder vor Ersatz stoppen:
test_main.pystellt sicher, dass der Recorder gestoppt wird, bevor er durch Config-Reload ersetzt wird (Commit1f8adc5).