test: cover setup() paths and reach 100% coverage#76
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #76 +/- ##
============================================
+ Coverage 73.68% 100.00% +26.31%
============================================
Files 1 1
Lines 38 38
Branches 3 3
============================================
+ Hits 28 38 +10
+ Misses 10 0 -10 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| async def main(): | ||
| loop = asyncio.get_running_loop() | ||
| called_in_executor = {"value": False} | ||
| original_run_in_executor = loop.run_in_executor |
There was a problem hiding this comment.
Agreed. The hackiness has three parts worth fixing together:
- Async harness mismatch — every other async test in this file uses
@pytest.mark.asyncio, but this one wraps an innermain()inasyncio.run(). That alone makes it stand out. monkeypatch.setattr(loop, "run_in_executor", tracker)— patching a bound method on a live event-loop instance via pytest's monkeypatch is fragile and reads ad-hoc. Swapping inunittest.mock.patch.object(loop, "run_in_executor", wraps=loop.run_in_executor)gives you a real spy withassert_called_once()and proper cleanup via the context manager.- Misleading name —
test_bluetooth_device_setup_runs_in_executor_via_asyncactually exercisesUARTDevice.async_setup. Rename totest_uart_device_async_setup_uses_executor.
Suggested rewrite:
@pytest.mark.asyncio
async def test_uart_device_async_setup_uses_executor(monkeypatch, tmp_path):
monkeypatch.setattr("uart_devices.UART_DEVICE_PATH", tmp_path)
_write_uevent(tmp_path / "serial0-0", "OF_COMPATIBLE_0=brcm,bcm43438-bt\n")
device = UARTDevice("serial0-0")
loop = asyncio.get_running_loop()
with mock.patch.object(loop, "run_in_executor", wraps=loop.run_in_executor) as spy:
await device.async_setup()
spy.assert_called_once()
assert device.manufacturer == "brcm"Alternative: just delete this test. test_uart_device_async_setup already proves the coroutine populates the fields correctly, and "did it call run_in_executor?" is implementation detail rather than observable behaviour. Happy to go either way — your call.
bdraco
left a comment
There was a problem hiding this comment.
fix run_in_executor hack to be proper pytest
PR Review — test: cover setup() paths and reach 100% coverageCoverage expansion from 68% → 100% is welcome and the fake-sysfs approach (writing real 🟡 Important1. Replace manual monkeypatch-on-loop with a real pytest-asyncio test + mock spy (`tests/test_init.py`, L149-176)Reviewer @bdraco flagged this as hacky and the request is fair. Three concrete problems:
Suggested replacement: @pytest.mark.asyncio
async def test_uart_device_async_setup_uses_executor(monkeypatch, tmp_path):
monkeypatch.setattr("uart_devices.UART_DEVICE_PATH", tmp_path)
_write_uevent(tmp_path / "serial0-0", "OF_COMPATIBLE_0=brcm,bcm43438-bt\n")
device = UARTDevice("serial0-0")
loop = asyncio.get_running_loop()
with mock.patch.object(loop, "run_in_executor", wraps=loop.run_in_executor) as spy:
await device.async_setup()
spy.assert_called_once()
assert device.manufacturer == "brcm"Alternatively, since 🟢 Suggestions1. Redundant `device.path = ...` reassignment after monkeypatching the module constant (`tests/test_init.py`, L42-46)
The same applies to every other setup test (lines 55, 64, 73, 100–101 for Checklist
SummaryCoverage expansion from 68% → 100% is welcome and the fake-sysfs approach (writing real To rebase specific severity levels, mention me: |
Adds tests for BluetoothDevice.setup, UARTDevice.setup, their async wrappers, uevent parsing edge cases (missing fields, MODALIAS without comma), and a check that async_setup offloads to the executor. Brings coverage from 68% to 100%.
Rebase with requested adjustmentsBranch Changes applied
StatsActions performed
CI statusCI will be checked asynchronously. Automated by Kōan |
4132645 to
d6e9279
Compare
What
Expand
tests/test_init.pyfrom 2 constructor-only tests to 11 tests covering the previously-untestedsetup()andasync_setup()paths on bothBluetoothDeviceandUARTDevice.Why
The library was at 68% coverage with all the actual sysfs-parsing logic (lines 37, 41-43, 67, 71-79) untested. The
setup()methods are where bugs would actually live; the constructors are trivial.How
monkeypatchto redirectBLUETOOTH_DEVICE_PATH/UART_DEVICE_PATHto atmp_path-rooted fake sysfs.ueventcontent and adevicesymlink to exercisePath.readlink()and theOF_COMPATIBLE_0/MODALIASparsers.MODALIASwithout a comma.async_setupactually offloads toloop.run_in_executor.Testing
poetry run pytest --cov=uart_devices→ 11 passed, 100% coverage (was 68%).Quality Report
Changes: 1 file changed, 158 insertions(+), 1 deletion(-)
Code scan: clean
Tests: passed (11 passed)
Branch hygiene: clean
Generated by Kōan post-mission quality pipeline