libuniset2 — библиотека для создания АСУ. Лучше один раз увидеть…Часть 5 (uniset2-testsuite)

    В предыдущих частях (часть 1, часть 2, часть 3, часть 4) было описано создание двух процессов имитатора и процесса управления и предварительная наладка. А теперь я хотел рассказать о написании функциональных тестов и предназначенного специально для этого средства под названием uniset2-testsuite.

    Вводная


    В общем случае, тестирование сводиться к идее "Подать тестовое воздействие, проверить реакцию". Т.к. в uniset-системе всё при помощи датчиков то и тестирование сводится к тому, чтобы выставить какие-то датчики и проверить по другим датчикам реакцию системы (Именно системы, т.к. функции могут выполнятся группой процессов и возможно раскиданных по разным узлам).
    Эта идея была положена в основу небольшого тестового фрэймворка для проектов на базе libuniset. И называется он uniset2-testsuite. Вообще это даже не фрэймворк, а просто программа (на python) умеющая проигрывать «тестовые сценарии» записанные в виде xml и позволяющая делать различные проверки на uniset-датчиках. Полное описание возможностей можно увидеть в небольшой документации здесь.

    А я попробую показать как это делается на примере тестирования нашего процесса управления.

    Создание тестового сценария


    Итак на текущий момент у нас уже есть следующие компоненты в нашем проекте
    • имитатор — который мы «вручную» протестировали здесь
    • процесс управления — который мы собираемся тестировать
    • SharedMemory — обязательная часть (хранение текущего состояния датчиков)

    Наш тест подразумевает, что он будет самодостаточным. Т.е. запустили тест, он сам запустил все необходимые программы, провёл тестирование и завершил программы, выдав отчёт.
    А также, для создания тестового сценария, нужно продумать, о том, что мы хотим проверить. Исходя из анализа нашего исходного задания можно выделить следующие простые проверки:
    • Процесс управления ничего не должен делать пока не пришла команда «начать работу»
    • Когда пришла команда процесс управления должен то наполнять «цистерну», то «опустошать».
    • Когда «снялась» команда «начать работу» — процесс управления должен прекратить работу

    Попробуем записать всё это в виде тестового сценария...

    В общем виде структура сценария выглядит следующим образом:
    <?xml version="1.0" encoding="utf-8"?>
    <TestScenario>
    <RunList>
       ..секция где описывается какие программы нужно запустить (а потом и остановить)
    </RunList>
    <TestList>
     <test name="XXX" comment="zzz">
        ...проверки...
     </test>
       <test name="YYY" comment="yyy">
        ...проверки...
      </test>
       ...
    </TestList>
    </TestScenario>
    

    Для нашего случая секция RunList примет вид
    <RunList after_run_pause="3000">
      <item after_run_pause="500" chdir="../../../SharedMemory" name="SharedMemory" script="./start_fg.sh" silent_mode="1"/>
      <item chdir="../../Imitator" name="imitator" script="./start_fg.sh" silent_mode="1"/>
      <item chdir="../" name="controller" script="./start_fg.sh" silent_mode="1"/>
    </RunList>
    

    Все возможные поля расписаны достаточно подробно в документации к uniset2-testsuite, поэтому не буду останавливаться. Тут видно, что мы просто перечислили какие процессы нам нужно запустить.

    Переходим собственно к записи тестов.
    Первая проверка, что процесс «ничего не делает». Т.к. результатом деятельности процесса управления является изменение датчика уровня Level_AS (ну ещё конечно выставление команд управления), то мы можем переформулировать «ничего не делает» в «датчики не изменяются какое-то достаточное время».
    Запишем…
    <test name="Stopped">
     <check test="CmdLoad_C=0" comment="Проверка что команда 'наполнить' не меняется" holdtime="3000"/>
     <check test="CmdUnload_C=0" comment="Проверка что команда 'опустошить' не меняется" holdtime="3000"/>
     <check test="Level_AS=0" comment="Проверка что уровень не меняется" holdtime="6000"/>
    </test>
    

    Т.е. мы проверяем что датчики не меняются в течение заданного времени (holdtime).

    Второй тест, это надо проверить собственно работу после подачи команды. Т.е. мы подаём команду «начать работу»(OnControl_S=1), процесс управления подаёт команду «наполняем»(CmdLoad_C=1), уровень в «цистерне» начинает увеличиваться и доходит до верхней планки (не обязательно проверять порог, главное зафиксировать, что меняется).
    Дальше процесс управления должен начать «опустошать» цистерну, подав команду «опустошение»(CmdUnload_C=0) и уровень должен снизиться до какого-то уровня. В целом этого достаточно для проверки того, что процесс работает.
    Запишем в тест…
    Текст теста
    <test name="Processing" comment="Проверка работы процесса">
      <action set="OnContol_S=1" comment="Подаём команду 'начать работу'"/>
      <check test="CmdLoad_C=1" comment="Подана команда 'наполнение'"/>
      <check test="CmdUnload_C=0" comment="Нет команда 'опустошение'"/>
      <check test="Level_AS>=90" comment="Цистерна наполняется.." timeout="15000"/>
      <check test="CmdLoad_C=0" comment="Снята команда 'наполнение'"/>
      <check test="CmdUnload_C=1" comment="Подана команда 'опустошение'"/>
      <check test="Level_AS<=10" comment="Цистерна опустошается.." timeout="15000"/>
    </test>
    



    И последняя проверка: Что при снятии команды «начать работу», процесс останавливается.
    Текст теста
    <test name="Stopped" comment="Проверка остановки процесса">
      <action set="OnContol_S=0" comment="Снимаем команду 'начать работу'"/>
      <check test="CmdLoad_C=0" comment="Проверка что команда 'наполнить' не меняется" holdtime="3000"/>
      <check test="CmdUnload_C=0" comment="Проверка что команда 'опустошить' не меняется" holdtime="3000"/>
      <check test="Level_AS<=80" comment="Уровень не меняется" holdtime="10000"/>
    </test>
    


    Тут единственная тонкость в том, что мы не знаем на каком уровне завершился предыдущий тест, знаем только, что цистерна опустошалась. Поэтому для проверки того, что ничего не происходит, мы проверяем что уровень не поднимается > 80 заданное время.

    В итоге полная версия нашего тестового сценария будет такой
    Тестовый сценарий
    <?xml version="1.0" encoding="utf-8"?>
    <TestScenario>
     <RunList after_run_pause="3000">
       <item after_run_pause="500" chdir="../../../SharedMemory" name="SharedMemory" script="./start_fg.sh" silent_mode="1"/>
       <item chdir="../../Imitator" name="imitator" script="./start_fg.sh" silent_mode="1"/>
       <item chdir="../" name="controller" script="./start_fg.sh" silent_mode="1"/>
     </RunList>
     <TestList>
      <test name="Stopped" comment="Проверка что без команды 'ничего не делаем'">
       <action set="OnControl_S=0" comment="Снимаем команду 'начать работу'"/>
       <check test="CmdLoad_C=0" comment="команда 'наполнить' не меняется" holdtime="3000"/>
       <check test="CmdUnload_C=0" comment="команда 'опустошить' не меняется" holdtime="3000"/>
       <check test="Level_AS=0" comment="уровень не меняется" holdtime="6000"/>
      </test>
      <test name="Processing" comment="Проверка работы процесса">
       <action set="OnControl_S=1" comment="Подаём команду 'начать работу'"/>
       <check test="CmdLoad_C=1" comment="Подана команда 'наполнение'"/>
       <check test="CmdUnload_C=0" comment="Cнята команда 'опустошение'"/>
       <check test="Level_AS>=90" comment="Цистерна наполняется.." timeout="15000"/>
       <check test="CmdLoad_C=0" comment="Снята команда 'наполнение'"/>
       <check test="CmdUnload_C=1" comment="Подана команда 'опустошение'"/>
       <check test="Level_AS<=10" comment="Цистерна опустошается.." timeout="15000"/>
      </test>
      <test name="Stopped" comment="Проверка остановки процесса">
       <action set="OnControl_S=0" comment="Снимаем команду 'начать работу'"/>
       <check test="CmdLoad_C=0" comment="команда 'наполнить' не меняется" holdtime="3000"/>
       <check test="CmdUnload_C=0" comment="команда 'опустошить' не меняется" holdtime="3000"/>
       <check test="Level_AS<=80" comment="Уровень не меняется" holdtime="10000"/>
      </test>
    </TestList>
    </TestScenario>
    



    Запуск теста


    Для запуска теста создадим небольшой скрипт
    #!/bin/sh
    uniset2-start.sh -f uniset2-testsuite-xmlplayer --confile configure.xml --testfile tests.xml --show-test-log --show-result-report --show-comments --show-action-log $*
    

    запускающий «проигрыватель тестов» с нашим сценарием.
    Переходим в каталог src/Algorithms/Controller/test-suite/ запускаем ./01-tests.sh и вот что мы должны увидеть:


    Вот собственно и всё с функциональным тестированием.
    Хочу только отметить, что это был простой демонстрационный тест. А в целом uniset2-testsuite позволяет писать сложные многосоставные тесты, ссылаться на другие тестовые файлы (строить тестовые иерархии), делать в тестах «автозамены» (т.е. по сути аналог «шаблонов»), работать с датчиками не разных узлах (по сети), сохранять отчёты в формате junit, писать сценарии работающие по протоколу ModbusTCP (т.е. можно тестировать не только uniset-проекты) и т.п. Всё это отражено в документации.

    Пока писал эти статьи, понял, что много чего осталось «за кадром». Поэтому будет ещё и «заключительная часть»..
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 0

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.