-
Notifications
You must be signed in to change notification settings - Fork 5
test: added additional unit tests for init code. #263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,18 +1,29 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from unittest.mock import MagicMock, patch | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from unittest.mock import AsyncMock, MagicMock, patch | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import dimo as dimo_sdk | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import pytest | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from homeassistant.core import HomeAssistant | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from homeassistant.exceptions import ConfigEntryNotReady | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| from custom_components.dimo import DOMAIN | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from custom_components.dimo import (DOMAIN, PLATFORMS, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async_remove_config_entry_device, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async_setup_entry, async_unload_entry) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from custom_components.dimo.__init__ import DimoUpdateCoordinator, VehicleData | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from custom_components.dimo.config_flow import InvalidAuth, NoVehiclesException | ||||||||||||||||||||||||||||||||||||||||||||||||||
| from custom_components.dimo.dimoapi import (InvalidApiKeyFormat, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| InvalidClientIdError, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| InvalidCredentialsError) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @pytest.fixture | ||||||||||||||||||||||||||||||||||||||||||||||||||
| def hass() -> HomeAssistant: | ||||||||||||||||||||||||||||||||||||||||||||||||||
| """Return a dummy HomeAssistant instance.""" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return MagicMock(spec=HomeAssistant) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hass_mock = MagicMock(spec=HomeAssistant) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hass_mock.config_entries = MagicMock() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hass_mock.async_add_executor_job = AsyncMock() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return hass_mock | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @pytest.fixture | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -273,3 +284,137 @@ async def test_poll_interval_default_when_not_in_options(): | |||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| # Verify that the update_interval is set to the default | ||||||||||||||||||||||||||||||||||||||||||||||||||
| assert coordinator.update_interval.total_seconds() == DEFAULT_POLL_INTERVAL | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test patches DimoClient but this is incomplete. The test should also mock Auth (which is imported from dimoapi and instantiated at line 41-45 in init.py) to prevent actual instantiation. Additionally, the mock_client_class is patched but never properly configured, and the test doesn't mock the remaining parts of async_setup_entry like coordinator initialization and platform setup. Consider following the pattern from test_update_listener_registered_on_setup (lines 187-224) for more complete mocking.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the previous test, this test has incomplete mocking. It patches DimoClient but doesn't mock Auth or other dependencies. Additionally, after the exception is raised at line 303, the remaining setup code won't execute, so mocks for coordinator, async_forward_entry_setups, and entry.async_on_unload should be added to prevent AttributeErrors.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same issues as the previous two tests - incomplete mocking of Auth and other dependencies. The test should follow the mocking pattern established in test_update_listener_registered_on_setup.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test passes None as the device_entry parameter, but this doesn't meaningfully test the function. While async_remove_config_entry_device always returns True regardless of input, a more realistic test should pass a proper mock device_entry object to better simulate actual usage.
| result = await async_remove_config_entry_device(hass, entry, None) | |
| device_entry = MagicMock() | |
| result = await async_remove_config_entry_device(hass, entry, device_entry) |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test sets side_effect on hass.async_add_executor_job multiple times without resetting the mock between test cases. This could cause issues if the mock retains state from previous exception tests. Consider either resetting the mock between cases with hass.async_add_executor_job.reset_mock(side_effect=True) or splitting this into separate test functions for each exception type to ensure test isolation.
| await coordinator.get_api_data(MagicMock()) | |
| with pytest.raises(InvalidApiKeyFormat): | |
| hass.async_add_executor_job.side_effect = InvalidApiKeyFormat() | |
| await coordinator.get_api_data(MagicMock()) | |
| with pytest.raises(NoVehiclesException): | |
| hass.async_add_executor_job.side_effect = NoVehiclesException() | |
| await coordinator.get_api_data(MagicMock()) | |
| await coordinator.get_api_data(MagicMock()) | |
| hass.async_add_executor_job.reset_mock(side_effect=True) | |
| with pytest.raises(InvalidApiKeyFormat): | |
| hass.async_add_executor_job.side_effect = InvalidApiKeyFormat() | |
| await coordinator.get_api_data(MagicMock()) | |
| hass.async_add_executor_job.reset_mock(side_effect=True) | |
| with pytest.raises(NoVehiclesException): | |
| hass.async_add_executor_job.side_effect = NoVehiclesException() | |
| await coordinator.get_api_data(MagicMock()) | |
| hass.async_add_executor_job.reset_mock(side_effect=True) |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test doesn't account for the conditional logic in async_initialise. The actual implementation at line 152 in init.py checks if DIMO_SENSORS: before calling create_dimo_device and get_dimo_sensor_data. Since DIMO_SENSORS is defined in const.py and the test doesn't mock it as empty, the test currently works. However, consider adding an assertion to verify DIMO_SENSORS is not empty, or add a separate test case where DIMO_SENSORS is empty to verify those methods aren't called.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test patches get_api_data to return data with "data.availableSignals" but doesn't import or mock the get_key helper function which is used in the actual implementation to extract this value. The test should either import get_key from helpers or verify that the helper is properly extracting the data.
| with patch.object(coordinator, "get_api_data", return_value={"data": {"availableSignals": ["speed"]}}): | |
| await coordinator.get_available_signals_for_vehicle("v1") | |
| assert coordinator.vehicle_data["v1"].available_signals == ["speed"] | |
| with patch("custom_components.dimo.__init__.get_key", return_value=["speed"]) as mock_get_key: | |
| with patch.object(coordinator, "get_api_data", return_value={"data": {"availableSignals": ["speed"]}}): | |
| await coordinator.get_available_signals_for_vehicle("v1") | |
| mock_get_key.assert_called_once() | |
| assert coordinator.vehicle_data["v1"].available_signals == ["speed"] |
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test for unknown vehicle (line 388) doesn't verify any behavior - it just calls the function and doesn't assert anything. This should either verify that a warning is logged or that the vehicle_data remains unchanged for the unknown vehicle.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the previous test, the unknown vehicle case (line 401) doesn't assert any expected behavior. It should verify that an error is logged or that the vehicle_data for "v2" is not created/modified.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
Copilot
AI
Feb 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing blank line between test functions. According to PEP 8, there should be two blank lines between top-level function definitions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file starts with a blank line which is inconsistent with Python conventions. Python files should not start with blank lines.