tests: mock the libnotify backend so the suite raises no real notifications

The desktop_notifications tests called the real init/alert/show, which
reach the libnotify daemon — every test run popped real GNOME
notifications titled "MockDevice" and "unknown".

Add an autouse conftest fixture that swaps Notify for a mock in both
desktop_notifications modules (solaar.ui and logitech_receiver). The
tests still exercise the real init/alert/show code paths, but
Notification.show() never reaches the daemon. The fixture returns the
mock; the notification tests now assert show() was actually dispatched
against it, so they verify the path instead of just "didn't crash".
This commit is contained in:
Ken Sanislo 2026-05-15 12:48:01 -07:00 committed by Peter F. Patel-Schneider
parent eefa37d83f
commit 4c709ecb73
3 changed files with 48 additions and 16 deletions

View File

@ -1,3 +1,7 @@
import importlib
from unittest import mock
import pytest import pytest
@ -16,3 +20,24 @@ def isolate_solaar_configuration(tmp_path, monkeypatch):
monkeypatch.setattr(configuration, "_yaml_file_path", str(tmp_path / "config.yaml")) monkeypatch.setattr(configuration, "_yaml_file_path", str(tmp_path / "config.yaml"))
monkeypatch.setattr(configuration, "_json_file_path", str(tmp_path / "config.json")) monkeypatch.setattr(configuration, "_json_file_path", str(tmp_path / "config.json"))
monkeypatch.setattr(configuration, "_config", []) monkeypatch.setattr(configuration, "_config", [])
@pytest.fixture(autouse=True)
def mock_desktop_notifications(monkeypatch):
"""Swap the libnotify backend for a mock in both desktop_notifications
modules. Tests still exercise the real init/alert/show code paths, but
Notification.show() never reaches the daemon without this the suite
raises real 'MockDevice' / 'unknown' notifications on every run.
Returns the Notify mock so notification tests can assert against it."""
notify = mock.MagicMock(name="Notify")
notify.is_initted.return_value = True
notify.init.return_value = True
for modname in ("solaar.ui.desktop_notifications", "logitech_receiver.desktop_notifications"):
try:
module = importlib.import_module(modname)
except Exception:
continue
monkeypatch.setattr(module, "Notify", notify, raising=False)
monkeypatch.setattr(module, "_notifications", {}, raising=False)
return notify

View File

@ -2,7 +2,9 @@ from unittest import mock
from logitech_receiver import desktop_notifications from logitech_receiver import desktop_notifications
# depends on external environment, so make some tests dependent on availability # The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the
# libnotify backend for a mock, so these exercise the real code paths without
# raising real desktop notifications.
def test_init(): def test_init():
@ -22,8 +24,11 @@ class MockDevice(mock.Mock):
return True return True
def test_show(): def test_show(mock_desktop_notifications):
dev = MockDevice() result = desktop_notifications.show(MockDevice(), "unknown")
reason = "unknown"
result = desktop_notifications.show(dev, reason) if desktop_notifications.available:
assert result is not None if desktop_notifications.available else result is None assert result is not None
mock_desktop_notifications.Notification.return_value.show.assert_called()
else:
assert result is None

View File

@ -2,7 +2,9 @@ from unittest import mock
from solaar.ui import desktop_notifications from solaar.ui import desktop_notifications
# depends on external environment, so make some tests dependent on availability # The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the
# libnotify backend for a mock, so these exercise the real code paths without
# raising real desktop notifications.
def test_init(): def test_init():
@ -15,9 +17,11 @@ def test_uninit():
assert desktop_notifications.uninit() is None assert desktop_notifications.uninit() is None
def test_alert(): def test_alert(mock_desktop_notifications):
reason = "unknown" assert desktop_notifications.alert("unknown") is None
assert desktop_notifications.alert(reason) is None
if desktop_notifications.available:
mock_desktop_notifications.Notification.return_value.show.assert_called()
class MockDevice(mock.Mock): class MockDevice(mock.Mock):
@ -27,13 +31,11 @@ class MockDevice(mock.Mock):
return True return True
def test_show(): def test_show(mock_desktop_notifications):
dev = MockDevice() result = desktop_notifications.show(MockDevice(), "unknown")
reason = "unknown"
available = desktop_notifications.init()
result = desktop_notifications.show(dev, reason) if desktop_notifications.available:
if available:
assert result is not None assert result is not None
mock_desktop_notifications.Notification.return_value.show.assert_called()
else: else:
assert result is None assert result is None