Практика: Написание тест-кейсов для сценария 'Я ушел'
Декомпозиция сценария 'Я ушел': от логики к тест-кейсам
Комплексный сценарий, такой как 'Я ушел', является одним из краеугольных камней любой серьезной системы автоматизации. Его критичность определяется двумя основными факторами: безопасностью (активация охранных систем, контроль доступа) и энергоэффективностью (отключение неиспользуемых потребителей, перевод климата в экономичный режим). Ошибка в этом сценарии может привести либо к ложной тревоге и потере доверия к системе, либо к реальным убыткам из-за невыключенного оборудования или, что хуже, к незащищенности объекта.
Для того чтобы написать исчерпывающие тест-кейсы, необходимо сначала декомпозировать сценарий, то есть разбить его на логические компоненты. Любой сценарий можно представить в виде трехсоставной структуры:
Давайте применим эту модель к нашему сценарию 'Я ушел':
| Компонент | Примеры для сценария 'Я ушел' |
| :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------- |
| Триггеры | - Нажатие физической кнопки 'Ушел' у входной двери (подключена к дискретному входу контроллера).
- Активация через мобильное приложение (команда по MQTT).
- Постановка на охрану с клавиатуры охранной системы (интеграция по Modbus или API).
- Уход последнего человека из геозоны 'Дом'. |
| Логика | - Проверка предусловий: Все ли окна и двери закрыты? Нет ли активных датчиков протечки?
- Проверка состояния: Система уже находится в режиме 'Я ушел'? Кто именно уходит (владелец, гость)?
- Принятие решений: Если открыто окно, отменить запуск и уведомить пользователя. Если все в порядке, продолжить выполнение. |
| Действия | - Освещение: Погасить весь свет в доме (команды по DALI, KNX или на релейные выходы контроллера).
- Климат: Перевести все термостаты/кондиционеры в режим 'Эко' (+2°C к уставке зимой, +4°C летом). (команды по Modbus, KNX).
- Безопасность: Поставить систему на охрану в режим 'Периметр' (закрытие замков, активация датчиков на окнах).
- Энергосбережение: Отключить все "неважные" розеточные группы (релейные выходы).
- Мультимедиа: Выключить все телевизоры и аудиосистемы.
- Уведомления: Отправить PUSH-уведомление "Режим 'Я ушел' активирован" владельцу. |
Ключевым шагом является составление карты зависимостей. Например, постановка на охрану должна происходить только после успешного получения подтверждения, что все окна закрыты. Отключение розеток на кухне должно произойти после выключения света, чтобы избежать ситуации, когда сначала пропадает питание управляющего модуля освещения, а потом отправляется команда на выключение.
Эта карта может выглядеть так:
`Триггер -> Проверка окон -> Проверка дверей -> (Если ОК) -> Выключить свет -> Выключить мультимедиа -> Перевести климат в 'Эко' -> Отключить розетки -> Поставить на охрану -> Отправить PUSH-уведомление.`
Если на любом из шагов "Проверка" результат отрицательный, цепочка прерывается и выполняется альтернативное действие (например, отправка PUSH-уведомления "Не могу включить охрану, открыто окно в спальне").
> 💡 Подсказка: При декомпозиции всегда думайте об обратном действии — сценарии 'Я пришел'. Успешное тестирование 'Я ушел' должно создавать корректные начальные условия для возвращения пользователя. Это смежные и взаимозависимые тесты. Например, если 'Я ушел' переводит климат в режим 'Эко', то 'Я пришел' должен вернуть его в 'Комфорт', а не просто включить.
---
Практика: Написание позитивных тест-кейсов ('Happy Path')
Позитивное тестирование (или "тестирование счастливого пути") проверяет, что система работает корректно при штатных условиях, когда все идет по плану. Это первый и обязательный шаг в тестировании любого сценария. Наша задача — убедиться, что при стандартном триггере выполняются все запланированные действия.Для этого мы формализуем наши проверки в виде тест-кейсов. Каждый тест-кейс должен иметь строгую структуру.
Формализация тест-кейса
| Поле | Описание |
| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| ID | Уникальный идентификатор (например, `TC-AWAY-001`). |
| Название | Краткое и понятное описание сути теста (например, "Штатная активация режима 'Я ушел' через кнопку на панели"). |
| Приоритет | Важность теста (например, High, Medium, Low). Для 'Happy Path' он всегда `High`. |
| Предусловия | Состояние системы, которое должно быть достигнуто перед началом теста (например, "Режим 'Дом' активен. Все окна и двери закрыты."). |
| Шаги выполнения | Последовательность действий, которые нужно выполнить для проведения теста. |
| Ожидаемый результат | Детальное описание того, как должна отреагировать система после выполнения шагов. Это самый важный пункт для оценки успеха. |
| Фактический результат | Заполняется после проведения теста. |
| Статус | `Пройден` / `Не пройден` / `Заблокирован`. |
Пример позитивного тест-кейса `TC-AWAY-001`
- ID: `TC-AWAY-001`
- Название: Штатная активация режима 'Я ушел' через симуляцию MQTT-команды.
- Приоритет: High
- Предусловия:
2. Все виртуальные датчики окон и дверей находятся в состоянии `closed`.
3. Освещение в гостиной и на кухне включено (`light.livingroom = ON`, `light.kitchen = ON`).
4. Климат-контроль в режиме 'Комфорт'.
- Шаги выполнения:
2. Опубликовать сообщение в топик `hi/system/commands/set_mode`.
3. В качестве `payload` использовать JSON: `{"mode": "away", "source": "test_panel"}`.
- Ожидаемый результат:
2. В течение 5 секунд климат-контроль переходит в режим 'Эко'. В MQTT-топике `hi/devices/hvac_main/stat/MODE` появляется сообщение `ECO`.
3. В течение 5 секунд в MQTT-топике `hi/system/state/HomeState` появляется сообщение `away` с флагом `retain=true`.
4. В течение 10 секунд на PUSH-шлюз отправляется уведомление с текстом "Режим 'Я ушел' активирован".
5. В логе аудита (таблица `audit_log` в MySQL) появляются записи обо всех выполненных действиях.
Симуляция в Node-RED
Для выполнения этого теста мы будем использовать узел `inject`, как мы это делали при изучении симуляции событий.
{
"mode": "away",
"source": "TC-AWAY-001"
}
При нажатии на `inject` вы должны увидеть в окне отладки поток сообщений от всех устройств, меняющих свое состояние. Ваша задача — сверить эти сообщения с "Ожидаемым результатом", обращая внимание на `msg.topic` и `msg.payload`.
---
Практика: Негативные и граничные тест-кейсы
> ⚠️ Внимание: Никогда не ограничивайтесь только 'счастливым путем'. Большинство проблем на объектах возникает из-за нештатных ситуаций, которые не были предусмотрены. Тестирование негативных и граничных случаев — ключевой показатель профессионализма инженера и залог надежности системы.
Негативное тестирование проверяет, как система реагирует на некорректные данные, нештатные условия и ошибки. Здесь мы проводим "мозговой штурм" на тему "А что, если...?".Тест-кейс `TC-AWAY-002`: Попытка ухода при открытом окне
- ID: `TC-AWAY-002`
- Название: Отмена активации режима 'Я ушел' из-за открытого окна на кухне.
- Приоритет: High
- Предусловия:
2. Виртуальный датчик `window_kitchen` установлен в состояние `open`. (Это можно сделать, отправив в `hi/devices/window_kitchen/stat/CONTACT` сообщение `OPEN`).
- Шаги выполнения:
- Ожидаемый результат:
2. Ни одно из действий (выключение света, смена режима климата) не происходит.
3. В течение 3 секунд на PUSH-шлюз отправляется уведомление с текстом "Невозможно активировать охрану. Открыто окно: Кухня".
4. Глобальное состояние `global.HomeState` остается `at_home`.
5. В логе аудита `audit_log` появляется запись об отказе с указанием причины.
Тест-кейс `TC-AWAY-003`: Недоступность одного из сервисов
Этот тест проверяет отказоустойчивость. Что произойдет, если одна из подсистем не ответит на команду?
- ID: `TC-AWAY-003`
- Название: Частичное выполнение сценария при недоступности климатической системы (Modbus-устройство).
- Приоритет: Medium
- Предусловия:
2. Имитация недоступности климатической системы. Простейший способ — временно деактивировать или изменить IP-адрес в настройках узла `Modbus-Client` в Node-RED, чтобы вызывать ошибку `timeout`.
- Шаги выполнения:
- Ожидаемый результат:
2. В системном логе ошибок (который обрабатывается узлом `Catch`) появляется запись об ошибке связи с Modbus-устройством (например, `Error: Modbus timeout for device HVAC`).
3. На PUSH-шлюз администратора (не пользователя!) отправляется уведомление "ОШИБКА: Не удалось перевести климат-контроль в режим 'Эко'".
4. Глобальное состояние`global.HomeState` корректно меняется на `away`. Сценарий не должен "зависнуть" из-за одной ошибки.
Тест-кейс `TC-AWAY-004`: Быстрый возврат (гонка состояний)
Гонка состояний — это классическая проблема в асинхронных системах. Пользователь нажимает "Ушел", но вспоминает, что забыл ключи, и через 2 секунды нажимает "Я дома". Система должна корректно обработать эту быструю смену состояний.- ID: `TC-AWAY-004`
- Название: Проверка на гонку состояний при быстрой смене режимов 'Ушел' -> 'Пришел'.
- Приоритет: Medium
- Предусловия:
- Шаги выполнения:
2. Подождать 2 секунды.
3. Опубликовать `{"mode": "at_home", "source": "test_panel"}` в тот же топик.
- Ожидаемый результат:
2. Не должно быть "зависших" процессов или циклов.
3. Финальное значение `global.HomeState` должно быть `at_home`.
4. В логах аудита должны быть записи о запуске обоих сценариев (или об отмене первого и запуске второго).
---
Интеграционное тестирование: Прямая проверка состояния устройств
До сих пор мы полагались на сообщения в MQTT, которые отправляет наша логика. Но отправила ли логика команду — это только половина дела. Выполнило ли ее конечное устройство? Интеграционное тестирование отвечает на этот вопрос, проверяя состояние оборудования напрямую, через его нативные протоколы.
Это уровень верификации, который отделяет симуляцию от реальности.
Пример 1: Проверка уставки термостата по KNX
После выполнения тест-кейса `TC-AWAY-001`, мы ожидаем, что уставка температуры на термостате в гостиной изменилась.
- Инструмент: Программное обеспечение ETS (инженерный инструмент для KNX) или консольная утилита `knxtool`.
- Действие: Нам нужно прочитать значение группового адреса, который отвечает за текущую уставку температуры (например, `3/1/1`).
- Верификация:
# Пример использования утилиты для чтения значения с KNX-шины
knxtool groupread ip:192.168.1.100 3/1/1
2. Сравниваем полученный результат с ожидаемым значением для режима 'Эко'. Если до ухода уставка была `22.0°C`, а в режиме 'Эко' она должна стать `24.0°C` (для лета), то мы должны получить значение `24.0`.
Пример 2: Проверка состояния реле по Modbus RTU
Сценарий выключает группу розеток, управляемую через Modbus-релейный модуль.
- Инструмент: Любая утилита для работы с Modbus (например, `mbpoll`, `Modbus Poll`).
- Действие: Нам нужно прочитать состояние `Coil` регистра, отвечающего за нужное реле. Допустим, это реле управляется `Coil` с адресом `16` на устройстве со `Slave ID = 5`.
- Верификация:
# Читаем 1 Coil, начиная с адреса 16, с устройства 5 на шине /dev/ttyRS485-1
mbpoll -a 5 -b 9600 -t 0 -c 1 -r 17 /dev/ttyRS485-1
# Обратите внимание: адресация часто начинается с 1, поэтому запрашиваем регистр 17.
2. Ожидаемый результат — `0`, что означает "выключено". Если до этого было `1` ("включено"), значит, команда отработала верно.
Пример 3: Проверка состояния лампы через MQTT
Это наиболее простой случай, так как мы уже использовали его для отладки. Но здесь мы выступаем в роли независимого наблюдателя.
- Инструмент: Любой MQTT-клиент (например, `MQTT Explorer`, `mosquitto_sub`).
- Действие: Подписываемся на статусный топик устройства. Например, для лампы в гостиной это может быть `hi/devices/light_livingroom/stat/POWER`.
# Подписаться на статусный топик с помощью консольного клиента
mosquitto_sub -h localhost -t 'hi/devices/light_livingroom/stat/POWER' -v
- Верификация: После запуска сценария 'Я ушел', мы должны получить в консоли сообщение `hi/devices/light_livingroom/stat/POWER OFF`. Важно также проверить `retain` флаг. Если он установлен, то даже новый подписчик сразу получит актуальное состояние.
---
Итоги и документирование: Фиксация результатов в Тест-плане
Написание и прогон тест-кейсов — это только часть работы. Без надлежащего документирования результатов эта работа теряет большую часть своей ценности. Каждый пройденный тест — это кирпичик в фундаменте уверенности, что система будет работать надежно.
> 🔗 Связанный материал: Все результаты должны быть оформлены в соответствии с шаблоном Тест-плана, который мы рассматривали в уроке `COURSE-07-M09-L02`. Для симуляции недоступности сети или устройств обращайтесь к техникам, описанным в уроке `COURSE-07-M09-L08: Проведение 'учений'`.
Процесс документирования
После выполнения каждого тест-кейса (например, `TC-AWAY-001`) вы открываете ваш документ Тест-плана и заполняете соответствующие поля:
* `Пройден (Passed)`: Все пункты ожидаемого результата выполнены.
* `Не пройден (Failed)`: Хотя бы один пункт не выполнен.
* `Заблокирован (Blocked)`: Тест невозможно провести из-за другой, более серьезной проблемы.
Работа с проваленными тестами
Если тест получил статус `Не пройден`, просто зафиксировать это недостаточно. Для быстрой и эффективной отладки необходимо:
- Прикрепить артефакты: К строке с тестом в Тест-плане приложите скриншоты окна `debug` в Node-RED, выдержки из системных логов (`journalctl` или `audit_log` из MySQL) и любые другие данные, которые помогут разработчику (или вам в будущем) понять причину сбоя.
- Описать расхождение: В поле "Комментарии" четко укажите, что именно пошло не так. "Ожидалось: свет выключится. Фактически: свет остался включенным, в логе ошибка `DALI bus busy`."
Создание набора регрессионных тестов
После того как вы исправили все ошибки и все тесты прошли успешно, вы создали первую стабильную версию сценария. Но работа над системой не заканчивается. В будущем вы будете добавлять новые функции или изменять старые. Как убедиться, что ваши изменения не сломали то, что уже работало?
Для этого существует регрессионное тестирование. Вы выбираете из всего списка тест-кейсов наиболее важные (обычно это все позитивные тесты и самые критичные негативные) и объединяете их в "регрессионный набор". Этот набор тестов необходимо будет выполнять каждый раз после внесения значимых изменений в логику системы.
Что дальше?
В этом уроке мы на практике разобрали, как от идеи сценария перейти к полноценному набору тестов, способных проверить его работоспособность в различных условиях. Мы научились декомпозировать логику, писать позитивные и негативные тест-кейсы, симулировать события и, что самое главное, проверять реальное состояние оборудования. Этот подход является основой для сдачи любого профессионально выполненного объекта заказчику. В следующем уроке мы перейдем к финальному этапу подготовки объекта — созданию пользовательской документации и инструкций по эксплуатации.