Skip to content

Commit

Permalink
Add some testing
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-r committed Dec 6, 2024
1 parent 47d702c commit 4030a40
Show file tree
Hide file tree
Showing 13 changed files with 417 additions and 6 deletions.
2 changes: 1 addition & 1 deletion custom_components/ohme/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def async_setup_entry(
CurrentSlotBinarySensor(coordinator, hass, client),
ChargerOnlineBinarySensor(coordinator_advanced, hass, client)]

async_add_entities(sensors, update_before_add=True)
await async_add_entities(sensors, update_before_add=True)


class ConnectedBinarySensor(
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def async_setup_entry(
OhmeApproveChargeButton(coordinator, hass, client)
)

async_add_entities(buttons, update_before_add=True)
await async_add_entities(buttons, update_before_add=True)


class OhmeApproveChargeButton(OhmeEntity, ButtonEntity):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async def async_setup_entry(
PriceCapNumber(coordinators[COORDINATOR_ACCOUNTINFO], hass, client)
)

async_add_entities(numbers, update_before_add=True)
await async_add_entities(numbers, update_before_add=True)


class TargetPercentNumber(OhmeEntity, NumberEntity):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async def async_setup_entry(
SlotListSensor(coordinator, hass, client),
BatterySOCSensor(coordinator, hass, client)]

async_add_entities(sensors, update_before_add=True)
await async_add_entities(sensors, update_before_add=True)


class PowerDrawSensor(OhmeEntity, SensorEntity):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ async def async_setup_entry(
"sleep_when_inactive", "power-sleep", "stealthEnabled")
)

async_add_entities(switches, update_before_add=True)
await async_add_entities(switches, update_before_add=True)


class OhmePauseChargeSwitch(OhmeEntity, SwitchEntity):
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async def async_setup_entry(
numbers = [TargetTime(coordinators[COORDINATOR_CHARGESESSIONS],
coordinators[COORDINATOR_SCHEDULES], hass, client)]

async_add_entities(numbers, update_before_add=True)
await async_add_entities(numbers, update_before_add=True)


class TargetTime(OhmeEntity, TimeEntity):
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
[tool.pytest.ini_options]
asyncio_mode = "auto"
filterwarnings = [
"ignore::RuntimeWarning"
]
70 changes: 70 additions & 0 deletions tests/test_binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import pytest
from unittest.mock import AsyncMock, MagicMock
from homeassistant.core import HomeAssistant
from homeassistant.util.dt import (utcnow)
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from custom_components.ohme.const import DOMAIN, DATA_CLIENT, DATA_SLOTS, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS, COORDINATOR_ADVANCED

from custom_components.ohme.binary_sensor import (
ConnectedBinarySensor,
ChargingBinarySensor,
PendingApprovalBinarySensor,
CurrentSlotBinarySensor,
ChargerOnlineBinarySensor,
)

@pytest.fixture
def mock_hass():
hass = MagicMock(spec=HomeAssistant)
hass.data = {
DOMAIN: {
"test_account": {
DATA_CLIENT: MagicMock(),
DATA_COORDINATORS: {
COORDINATOR_CHARGESESSIONS: MagicMock(spec=DataUpdateCoordinator),
COORDINATOR_ADVANCED: MagicMock(spec=DataUpdateCoordinator),
}
}
}
}
return hass

@pytest.fixture
def mock_coordinator():
return MagicMock(spec=DataUpdateCoordinator)

@pytest.fixture
def mock_client():
mock = MagicMock()
mock.email = "test_account"
return mock

def test_connected_binary_sensor(mock_hass, mock_coordinator, mock_client):
sensor = ConnectedBinarySensor(mock_coordinator, mock_hass, mock_client)
mock_coordinator.data = {"mode": "CONNECTED"}
assert sensor.is_on is True

mock_coordinator.data = {"mode": "DISCONNECTED"}
assert sensor.is_on is False

def test_charging_binary_sensor(mock_hass, mock_coordinator, mock_client):
sensor = ChargingBinarySensor(mock_coordinator, mock_hass, mock_client)
mock_coordinator.data = {"power": {"watt": 100}, "batterySoc": {"wh": 50}, "mode": "CONNECTED", "allSessionSlots": []}
sensor._last_reading = {"power": {"watt": 100}, "batterySoc": {"wh": 40}}
assert sensor._calculate_state() is True

def test_pending_approval_binary_sensor(mock_hass, mock_coordinator, mock_client):
sensor = PendingApprovalBinarySensor(mock_coordinator, mock_hass, mock_client)
mock_coordinator.data = {"mode": "PENDING_APPROVAL"}
assert sensor.is_on is True

mock_coordinator.data = {"mode": "CONNECTED"}
assert sensor.is_on is False

def test_charger_online_binary_sensor(mock_hass, mock_coordinator, mock_client):
sensor = ChargerOnlineBinarySensor(mock_coordinator, mock_hass, mock_client)
mock_coordinator.data = {"online": True}
assert sensor.is_on is True

mock_coordinator.data = {"online": False}
assert sensor.is_on is False
63 changes: 63 additions & 0 deletions tests/test_button.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
from custom_components.ohme.button import async_setup_entry, OhmeApproveChargeButton
from custom_components.ohme.const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS

@pytest.fixture
def mock_hass():
hass = MagicMock()
hass.data = {
DOMAIN: {
'test_account': {

}
}
}
return hass

@pytest.fixture
def mock_config_entry():
return AsyncMock(data={'email': '[email protected]'})

@pytest.fixture
def mock_client():
client = AsyncMock()
client.is_capable.return_value = True
client.async_approve_charge = AsyncMock()
return client

@pytest.fixture
def mock_coordinator():
coordinator = AsyncMock()
coordinator.async_refresh = AsyncMock()
return coordinator

@pytest.fixture
def setup_hass(mock_hass, mock_config_entry, mock_client, mock_coordinator):
mock_hass.data = {
DOMAIN: {
'[email protected]': {
DATA_CLIENT: mock_client,
DATA_COORDINATORS: {
COORDINATOR_CHARGESESSIONS: mock_coordinator
}
}
}
}
return mock_hass

@pytest.mark.asyncio
async def test_async_setup_entry(setup_hass, mock_config_entry):
async_add_entities = AsyncMock()
await async_setup_entry(setup_hass, mock_config_entry, async_add_entities)
assert async_add_entities.call_count == 1

@pytest.mark.asyncio
async def test_ohme_approve_charge_button(setup_hass, mock_client, mock_coordinator):
button = OhmeApproveChargeButton(mock_coordinator, setup_hass, mock_client)
await button.async_press()
mock_client.async_approve_charge.assert_called_once()
mock_coordinator.async_refresh.assert_called_once()
79 changes: 79 additions & 0 deletions tests/test_number.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from homeassistant.core import HomeAssistant
from custom_components.ohme.const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_ACCOUNTINFO, COORDINATOR_CHARGESESSIONS, COORDINATOR_SCHEDULES

from custom_components.ohme.number import (
async_setup_entry,
TargetPercentNumber,
PreconditioningNumber,
PriceCapNumber,
)

@pytest.fixture
def mock_hass():
hass = MagicMock(data = {
DOMAIN: {
"[email protected]": {
DATA_COORDINATORS: [
AsyncMock(),
AsyncMock(),
AsyncMock(),
AsyncMock()
],
DATA_CLIENT: AsyncMock()
}
}
})
return hass

@pytest.fixture
def mock_config_entry():
return AsyncMock(data={"email": "[email protected]"})

@pytest.fixture
def mock_async_add_entities():
return AsyncMock()

@pytest.mark.asyncio
async def test_async_setup_entry(mock_hass, mock_config_entry, mock_async_add_entities):
await async_setup_entry(mock_hass, mock_config_entry, mock_async_add_entities)
assert mock_async_add_entities.call_count == 1

@pytest.mark.asyncio
async def test_target_percent_number(mock_hass):
coordinator = mock_hass.data[DOMAIN]["[email protected]"][DATA_COORDINATORS][COORDINATOR_CHARGESESSIONS]
coordinator_schedules = mock_hass.data[DOMAIN]["[email protected]"][DATA_COORDINATORS][COORDINATOR_SCHEDULES]
client = mock_hass.data[DOMAIN]["[email protected]"][DATA_CLIENT]

number = TargetPercentNumber(coordinator, coordinator_schedules, mock_hass, client)

with patch('custom_components.ohme.number.session_in_progress', return_value=True):
await number.async_added_to_hass()
await number.async_set_native_value(50)

assert number._state is None or number._state == 50

@pytest.mark.asyncio
async def test_preconditioning_number(mock_hass):
coordinator = mock_hass.data[DOMAIN]["[email protected]"][DATA_COORDINATORS][COORDINATOR_CHARGESESSIONS]
coordinator_schedules = mock_hass.data[DOMAIN]["[email protected]"][DATA_COORDINATORS][COORDINATOR_SCHEDULES]
client = mock_hass.data[DOMAIN]["[email protected]"][DATA_CLIENT]

number = PreconditioningNumber(coordinator, coordinator_schedules, mock_hass, client)

with patch('custom_components.ohme.number.session_in_progress', return_value=True):
await number.async_added_to_hass()
await number.async_set_native_value(30)

assert number._state is None or number._state == 30

@pytest.mark.asyncio
async def test_price_cap_number(mock_hass):
coordinator = mock_hass.data[DOMAIN]["[email protected]"][DATA_COORDINATORS][COORDINATOR_ACCOUNTINFO]
client = mock_hass.data[DOMAIN]["[email protected]"][DATA_CLIENT]

number = PriceCapNumber(coordinator, mock_hass, client)
await number.async_set_native_value(10.0)

assert number._state is None or number._state == 10.0
31 changes: 31 additions & 0 deletions tests/test_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
from unittest.mock import MagicMock
from custom_components.ohme.sensor import VoltageSensor

@pytest.fixture
def mock_coordinator():
"""Fixture for creating a mock coordinator."""
coordinator = MagicMock()
return coordinator

@pytest.fixture
def voltage_sensor(mock_coordinator):
"""Fixture for creating a VoltageSensor instance."""
hass = MagicMock()
client = MagicMock()
return VoltageSensor(mock_coordinator, hass, client)

def test_voltage_sensor_native_value_with_data(voltage_sensor, mock_coordinator):
"""Test native_value when coordinator has data."""
mock_coordinator.data = {'power': {'volt': 230}}
assert voltage_sensor.native_value == 230

def test_voltage_sensor_native_value_no_data(voltage_sensor, mock_coordinator):
"""Test native_value when coordinator has no data."""
mock_coordinator.data = None
assert voltage_sensor.native_value is None

def test_voltage_sensor_native_value_no_power_data(voltage_sensor, mock_coordinator):
"""Test native_value when coordinator has no power data."""
mock_coordinator.data = {'power': None}
assert voltage_sensor.native_value is None
Loading

0 comments on commit 4030a40

Please sign in to comment.