Files
homecontrol.esp-sensors/tests/test_mqtt.py

161 lines
5.2 KiB
Python

"""
Tests for the MQTT module.
"""
import pytest
import json
from unittest.mock import patch, MagicMock
from src.esp_sensors.mqtt import setup_mqtt, publish_sensor_data, MQTTClient
class TestSensor:
"""Mock sensor class for testing."""
__test__ = False # Prevent pytest from treating this as a test case
def __init__(self, name="Test Sensor", temperature_unit="C"):
self.name = name
self.temperature_unit = temperature_unit
@pytest.fixture
def mqtt_config():
"""Fixture providing a sample MQTT configuration."""
return {
"enabled": True,
"broker": "test.mosquitto.org",
"port": 1883,
"client_id": "test_client",
"username": "test_user",
"password": "test_pass",
"topic_prefix": "test/sensors",
"publish_interval": 30,
"ssl": False,
"keepalive": 60,
}
@pytest.fixture
def disabled_mqtt_config():
"""Fixture providing a disabled MQTT configuration."""
return {
"enabled": False,
"broker": "test.mosquitto.org",
}
@pytest.fixture
def mock_sensor():
"""Fixture providing a mock sensor."""
return TestSensor(name="DHT22 Sensor", temperature_unit="C")
def test_setup_mqtt_disabled(disabled_mqtt_config):
"""Test that setup_mqtt returns None when MQTT is disabled."""
client = setup_mqtt(disabled_mqtt_config)
assert client is None
def test_setup_mqtt_enabled(mqtt_config):
"""Test that setup_mqtt creates and connects a client when MQTT is enabled."""
with patch("src.esp_sensors.mqtt.MQTTClient") as mock_mqtt_client:
# Configure the mock
mock_client_instance = MagicMock()
mock_mqtt_client.return_value = mock_client_instance
# Call the function
client = setup_mqtt(mqtt_config)
# Verify MQTTClient was created with correct parameters
mock_mqtt_client.assert_called_once_with(
mqtt_config["client_id"],
mqtt_config["broker"],
mqtt_config["port"],
mqtt_config["username"],
mqtt_config["password"],
mqtt_config["keepalive"],
mqtt_config["ssl"],
)
# Verify connect was called
mock_client_instance.connect.assert_called_once()
# Verify the client was returned
assert client == mock_client_instance
def test_setup_mqtt_connection_error(mqtt_config):
"""Test that setup_mqtt handles connection errors gracefully."""
with patch("src.esp_sensors.mqtt.MQTTClient") as mock_mqtt_client:
# Configure the mock to raise an exception on connect
mock_client_instance = MagicMock()
mock_client_instance.connect.side_effect = Exception("Connection failed")
mock_mqtt_client.return_value = mock_client_instance
# Call the function
client = setup_mqtt(mqtt_config)
# Verify connect was called
mock_client_instance.connect.assert_called_once()
# Verify None was returned due to the error
assert client is None
def test_publish_sensor_data_success(mqtt_config, mock_sensor):
"""Test that publish_sensor_data publishes to the correct topics."""
# Create a mock client
mock_client = MagicMock()
# Call the function
temperature = 25.5
humidity = 60.0
result = publish_sensor_data(
mock_client, mqtt_config, mock_sensor, temperature, humidity
)
# Verify the result
assert result is True
# Verify publish was called for temperature
temp_topic = f"{mqtt_config['topic_prefix']}/{mock_sensor.name.lower().replace(' ', '_')}/temperature"
mock_client.publish.assert_any_call(temp_topic, str(temperature).encode())
# Verify publish was called for humidity
humidity_topic = f"{mqtt_config['topic_prefix']}/{mock_sensor.name.lower().replace(' ', '_')}/humidity"
mock_client.publish.assert_any_call(humidity_topic, str(humidity).encode())
# Verify publish was called for combined data
data_topic = f"{mqtt_config['topic_prefix']}/{mock_sensor.name.lower().replace(' ', '_')}/data"
# Check that the JSON data was published
for call_args in mock_client.publish.call_args_list:
if call_args[0][0] == data_topic:
# Parse the JSON data
data = json.loads(call_args[0][1].decode())
assert data["temperature"] == temperature
assert data["humidity"] == humidity
assert data["unit"] == mock_sensor.temperature_unit
assert "timestamp" in data
break
else:
pytest.fail("Data topic was not published")
def test_publish_sensor_data_no_client(mqtt_config, mock_sensor):
"""Test that publish_sensor_data returns False when client is None."""
result = publish_sensor_data(None, mqtt_config, mock_sensor, 25.5, 60.0)
assert result is False
def test_publish_sensor_data_error(mqtt_config, mock_sensor):
"""Test that publish_sensor_data handles errors gracefully."""
# Create a mock client that raises an exception on publish
mock_client = MagicMock()
mock_client.publish.side_effect = Exception("Publish failed")
# Call the function
result = publish_sensor_data(mock_client, mqtt_config, mock_sensor, 25.5, 60.0)
# Verify the result
assert result is False