Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Клуб профессиональных программистов :: Выпуск #130


Клуб профессиональных программистов «Весельчак У»
Информационная рассылка сайта и форума.  Выпуск 130.  22 декабря 2011 г.

Здравствуйте, уважаемые читатели!



Сегодня предлагаем вам прочесть фрагмент статьи «Многозадачность во встроенном приложении. Часть 2».



Приятного чтения! Прощаемся с Вами до следующего выпуска.


С уважением, команда Клуба.


Оглавление



Каркас приложения


Построение каркаса приложения для микроконтроллера было подробно рассмотрено в статье «“Hello World!” в embedded-исполнении», поэтому здесь я не буду вдаваться в детали. Замечу лишь, что в данном проекте мы избежим возни с make-файлами, созданными вручную (это имело смысл сделать один раз, чтобы увидеть «изнанку» сборки проекта, но потребовало массу усилий, которые мы теперь будем экономить). На инструментальной системе я буду использовать среду разработки CodeBlocks.


Главная функция


Рис. 1. Главная функция программы.

Ранее мы уже обсуждали трудности, которые возникают при попытке модульного тестирования главной функции программы. Поэтому читателя уже не должно удивлять, что она фактически является вырожденной и лишь делегирует основную работу обычному модулю, который не имеет никаких особенностей и поэтому может быть протестирован без проблем (рис. 1).


Код: (Beacon.c)
#include "Application.h"

int main()
{
    Application_init();

    for (;;)
        Application_run();
}



Код: (Application.h)
#ifndef _APPLICATION_H
#define _APPLICATION_H

/** @file
 * @brief Интерфейс модуля Application.
 */

/**
 * @brief Инициализация приложения.
 *
 * Должна выполняться перед первым вызовом Application_run().
 */
void Application_init(void);

/**
 * @brief Итерация главного цикла приложения.
 */
void Application_run(void);

#endif // _APPLICATION_H

Модуль Application


Рис.2. Модуль Application.

На данном этапе единственная задача модуля Application (Рис. 2) — управление будущим конечным автоматом, который мы вскоре реализуем (в данный момент делать это еще рано, ведь наша разработка движется в направлении сверху-вниз, поэтому каждый модуль появляется на сцене только в тот момент, когда уже готов вышестоящий модуль-клиент, нуждающийся в его услугах).

Интерфейс автомата также будет иметь два основных метода. Первый (init()) приведет автомат в исходное состояние, при помощи второго (run()) модуль Application будет периодически «подталкивать» автомат, давая ему возможность оценить происшедшие события и при необходимости совершить переход в другое состояние согласно диаграмме. Для целей тестирования нам понадобится также метод getState(), при помощи которого мы можем запросить текущее состояние автомата; это даст нам возможность сравнить фактическое поведение автомата с желаемым.

Раз уж речь зашла о состояниях, определим тип RedChannelAuto_State для его описания.

Интерфейс автомата на языке C будет выглядеть таким образом:


Код: (RedChannelAuto.c)
#ifndef _REDCHANNELAUTO_H
#define _REDCHANNELAUTO_H

/** @file
 * @brief Интерфейс модуля RedChannelAuto.
 */

/**
 * @brief Инициализация модуля.
 *
 * Должна выполняться перед первым вызовом RedChannelAuto_run().
 */
void RedChannelAuto_init(void);

/**
 * @brief Итерация цикла модуля.
 */
void RedChannelAuto_run(void);

/**
 * @brief Состояние автомата.
 */
typedef enum
{
    LIGHT_OFF,
    LIGHT_ON
} RedChannelAuto_State;

/**
 * @brief Возвращает текущее состояние автомата
 */
RedChannelAuto_State RedChannelAuto_getState(void);

#endif // _REDCHANNELAUTO_H

Следуя типовой процедуре TDD, начнем разработку модуля с написания тестов, убедимся, что они сигнализируют об ошибке, а затем напишем код, который эти тесты успешно проходит.


Подставной объект RedChannelAuto


Как мы уже выяснили, при разработке «сверху-вниз» невозможно протестировать модуль без применения тестовых двойников модулей нижележащих уровней, которые использует тестируемый модуль. Поэтому первым делом нам следует сгенерировать подставной объект, используя интерфейс RedChannelAuto.c. Если вы забыли, как это делается, шпаргалка находится здесь.

Результат генерации:


Код: (MockRedChannelAuto.h)
/* AUTOGENERATED FILE. DO NOT EDIT. */
#ifndef _MOCKREDCHANNELAUTO_H
#define _MOCKREDCHANNELAUTO_H

#include "RedChannelAuto.h"

void MockRedChannelAuto_Init(void);
void MockRedChannelAuto_Destroy(void);
void MockRedChannelAuto_Verify(void);




#define RedChannelAuto_init_Expect() RedChannelAuto_init_CMockExpect(__LINE__)
void RedChannelAuto_init_CMockExpect(UNITY_LINE_TYPE cmock_line);
#define RedChannelAuto_run_Expect() RedChannelAuto_run_CMockExpect(__LINE__)
void RedChannelAuto_run_CMockExpect(UNITY_LINE_TYPE cmock_line);
#define RedChannelAuto_getState_ExpectAndReturn(cmock_retval) \
    RedChannelAuto_getState_CMockExpectAndReturn(__LINE__, cmock_retval)
void RedChannelAuto_getState_CMockExpectAndReturn(UNITY_LINE_TYPE \
    cmock_line, RedChannelAuto_State cmock_to_return);

#endif

Метод Application.init


...



Полностью прочитать статью можно на нашем сайте, в разделе «Инструменты и технологии проектирования ПО».



В избранное