Skip to content

Commit

Permalink
Working on tests
Browse files Browse the repository at this point in the history
  • Loading branch information
CJNE committed Jun 10, 2021
1 parent d0b61ed commit def65b6
Show file tree
Hide file tree
Showing 9 changed files with 714 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"github_user": "cjne",
"project_name": "ha-sunspec",
"test_suite": "yes",
"version": "0.0.1"
"version": "0.0.2"
}
2 changes: 1 addition & 1 deletion custom_components/sunspec/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
coordinator = hass.data[DOMAIN].pop(entry.entry_id)
coordinator.unsub()

return unloaded
return True # unloaded


async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/sunspec/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async def async_step_user(self, user_input=None):
self._abort_if_unique_id_configured(
updates={CONF_HOST: host, CONF_PORT: port, CONF_SLAVE_ID: slave_id}
)
return self.async_create_entry(title="", data=user_input)
return self.async_create_entry(title=f"{host}:{port}", data=user_input)

self._errors["base"] = "connection"

Expand Down
4 changes: 1 addition & 3 deletions custom_components/sunspec/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
NAME = "SunSpec"
DOMAIN = "sunspec"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "0.0.1"
VERSION = "0.0.2"

ATTRIBUTION = "Data provided by SunSpec alliance - https://sunspec.org"
ISSUE_URL = "https://github.com/cjne/ha-sunspec/issues"
Expand All @@ -15,9 +15,7 @@
BINARY_SENSOR_DEVICE_CLASS = "connectivity"

# Platforms
BINARY_SENSOR = "binary_sensor"
SENSOR = "sensor"
SWITCH = "switch"
PLATFORMS = [SENSOR]


Expand Down
14 changes: 12 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest.mock import patch

import pytest
import sunspec2.file.client as modbus_client

pytest_plugins = "pytest_homeassistant_custom_component"

Expand All @@ -23,8 +24,17 @@ def skip_notifications_fixture():
@pytest.fixture(name="bypass_get_data")
def bypass_get_data_fixture():
"""Skip calls to get data from API."""
with patch("custom_components.sunspec.SunSpecApiClient.async_get_data"), patch(
"custom_components.sunspec.SunSpecApiClient.get_client"
with patch("custom_components.sunspec.SunSpecApiClient.async_get_data"):
yield


@pytest.fixture(name="sunspec_client_mock", autouse=True)
def sunspec_client_mock():
"""Skip calls to get data from API."""
client = modbus_client.FileClientDevice("./tests/test_data/inverter.json")
client.scan()
with patch(
"custom_components.sunspec.SunSpecApiClient.modbus_connect", return_value=client
):
yield

Expand Down
11 changes: 4 additions & 7 deletions tests/const.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
"""Constants for SunSpec tests."""
from custom_components.sunspec.const import (
CONF_HOST,
)
from custom_components.sunspec.const import (
CONF_PORT,
)
from custom_components.sunspec.const import CONF_HOST
from custom_components.sunspec.const import CONF_PORT
from custom_components.sunspec.const import CONF_SLAVE_ID

MOCK_CONFIG = {CONF_HOST: "test_host", CONF_PORT: 123}
MOCK_CONFIG = {CONF_HOST: "test_host", CONF_PORT: 123, CONF_SLAVE_ID: 1}
134 changes: 79 additions & 55 deletions tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,57 @@
"""Tests for SunSpec api."""
import asyncio

import aiohttp
from custom_components.sunspec.api import (
SunSpecApiClient,
)


async def test_api(hass, aioclient_mock, caplog):
async def test_api(hass, aioclient_mock, caplog, sunspec_client_mock):
"""Test API calls."""

# To test the api submodule, we first create an instance of our API client
api = SunSpecApiClient(host="test", port=123, client_id=1, hass=hass)
api = SunSpecApiClient(host="test", port=123, slave_id=1, hass=hass)

# Use aioclient_mock which is provided by `pytest_homeassistant_custom_components`
# to mock responses to aiohttp requests. In this case we are telling the mock to
# return {"test": "test"} when a `GET` call is made to the specified URL. We then
# call `async_get_data` which will make that `GET` request.
aioclient_mock.get(
"https://jsonplaceholder.typicode.com/posts/1", json={"test": "test"}
)
assert await api.async_get_data(1) == {"test": "test"}
models = await api.async_get_models()

assert models == [
1,
701,
702,
703,
704,
705,
706,
707,
708,
709,
710,
711,
712,
713,
]

device_info = await api.async_get_device_info()

assert device_info.getValue("Mn") == "SunSpecTest"
assert device_info.getValue("SN") == "sn-123456789"

model = await api.async_get_data(701)
assert model.getValue("W") == 9800
assert model.getMeta("W")["label"] == "Active Power"

model = await api.async_get_data(705)
keys = model.getKeys()
assert len(keys) == 22

# We do the same for `async_set_title`. Note the difference in the mock call
# between the previous step and this one. We use `patch` here instead of `get`
# because we know that `async_set_title` calls `api_wrapper` with `patch` as the
# first parameter
aioclient_mock.patch("https://jsonplaceholder.typicode.com/posts/1")
assert await api.async_set_title("test") is None
# aioclient_mock.patch("https://jsonplaceholder.typicode.com/posts/1")
# assert await api.async_set_title("test") is None

# In order to get 100% coverage, we need to test `api_wrapper` to test the code
# that isn't already called by `async_get_data` and `async_set_title`. Because the
Expand All @@ -37,50 +61,50 @@ async def test_api(hass, aioclient_mock, caplog):
# The caplog fixture allows access to log messages in tests. This is particularly
# useful during exception handling testing since often the only action as part of
# exception handling is a logging statement
caplog.clear()
aioclient_mock.put(
"https://jsonplaceholder.typicode.com/posts/1", exc=asyncio.TimeoutError
)
assert (
await api.api_wrapper("put", "https://jsonplaceholder.typicode.com/posts/1")
is None
)
assert (
len(caplog.record_tuples) == 1
and "Timeout error fetching information from" in caplog.record_tuples[0][2]
)
# caplog.clear()
# aioclient_mock.put(
# "https://jsonplaceholder.typicode.com/posts/1", exc=asyncio.TimeoutError
# )
# assert (
# await api.api_wrapper("put", "https://jsonplaceholder.typicode.com/posts/1")
# is None
# )
# assert (
# len(caplog.record_tuples) == 1
# and "Timeout error fetching information from" in caplog.record_tuples[0][2]
# )

caplog.clear()
aioclient_mock.post(
"https://jsonplaceholder.typicode.com/posts/1", exc=aiohttp.ClientError
)
assert (
await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/1")
is None
)
assert (
len(caplog.record_tuples) == 1
and "Error fetching information from" in caplog.record_tuples[0][2]
)
# caplog.clear()
# aioclient_mock.post(
# "https://jsonplaceholder.typicode.com/posts/1", exc=aiohttp.ClientError
# )
# assert (
# await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/1")
# is None
# )
# assert (
# len(caplog.record_tuples) == 1
# and "Error fetching information from" in caplog.record_tuples[0][2]
# )

caplog.clear()
aioclient_mock.post("https://jsonplaceholder.typicode.com/posts/2", exc=Exception)
assert (
await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/2")
is None
)
assert (
len(caplog.record_tuples) == 1
and "Something really wrong happened!" in caplog.record_tuples[0][2]
)
# caplog.clear()
# aioclient_mock.post("https://jsonplaceholder.typicode.com/posts/2", exc=Exception)
# assert (
# await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/2")
# is None
# )
# assert (
# len(caplog.record_tuples) == 1
# and "Something really wrong happened!" in caplog.record_tuples[0][2]
# )

caplog.clear()
aioclient_mock.post("https://jsonplaceholder.typicode.com/posts/3", exc=TypeError)
assert (
await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/3")
is None
)
assert (
len(caplog.record_tuples) == 1
and "Error parsing information from" in caplog.record_tuples[0][2]
)
# caplog.clear()
# aioclient_mock.post("https://jsonplaceholder.typicode.com/posts/3", exc=TypeError)
# assert (
# await api.api_wrapper("post", "https://jsonplaceholder.typicode.com/posts/3")
# is None
# )
# assert (
# len(caplog.record_tuples) == 1
# and "Error parsing information from" in caplog.record_tuples[0][2]
# )
12 changes: 3 additions & 9 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@
from unittest.mock import patch

import pytest
from custom_components.sunspec.const import (
BINARY_SENSOR,
)
from custom_components.sunspec.const import (
DOMAIN,
)
Expand All @@ -14,9 +11,6 @@
from custom_components.sunspec.const import (
SENSOR,
)
from custom_components.sunspec.const import (
SWITCH,
)
from homeassistant import config_entries
from homeassistant import data_entry_flow
from pytest_homeassistant_custom_component.common import MockConfigEntry
Expand Down Expand Up @@ -60,7 +54,7 @@ async def test_successful_config_flow(hass, bypass_get_data):
# Check that the config flow is complete and a new entry is created with
# the input data
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "test_username"
assert result["title"] == "test_host:123"
assert result["data"] == MOCK_CONFIG
assert result["result"]

Expand All @@ -84,7 +78,7 @@ async def test_failed_config_flow(hass, error_on_get_data):
)

assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "auth"}
assert result["errors"] == {"base": "connection"}


# Our config flow also has an options flow, so we must test it as well.
Expand Down Expand Up @@ -114,4 +108,4 @@ async def test_options_flow(hass):
assert result["title"] == "test_username"

# Verify that the options were updated
assert entry.options == {BINARY_SENSOR: True, SENSOR: False, SWITCH: True}
# assert entry.options == {BINARY_SENSOR: True, SENSOR: False, SWITCH: True}
Loading

0 comments on commit def65b6

Please sign in to comment.