С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. - Инструментальные средства разработки ПО в ОС UNIX, страница 9
Описание файла
PDF-файл из архива "С.В. Герасимов, И.В. Машечкин, М.И. Петровский и др. - Инструментальные средства разработки ПО в ОС UNIX", который расположен в категории "". Всё это находится в предмете "операционные системы" из 3 семестр, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .
Просмотр PDF-файла онлайн
Текст 9 страницы из PDF
Функция установки вызывается один раз до запуска всех50тестов набора, функция очистки также один раз после работытестов. Указанные функции могут быть полезны длясоздания/освобождениявспомогательныхструктурданных,открытия/закрытия временных файлов и т.п. CUnit позволяетзапускать как тесты из заданных реестров и наборов, так иотдельные тесты.РеестрыCUnit создает один реестр тестов по умолчанию. До егоиспользования должна быть вызвана функция CU_initialize_registry.После завершения тестирования пользователь должен вызватьфункцию CU_cleanup_registry для освобождения памяти, занятойреестром. Данная функция должна быть последней вызваннойфункцией CUnit. Отсутствие вызова CU_cleanup_registry() приведетк утечке памяти.ФункцииCU_initialize_registryиCU_cleanup_registryоперируют единственным реестром, создаваемым по умолчанию.Для создания и управления дополнительными реестрами следуетиспользовать функции:CU_create_new_registry,CU_get_registry,CU_set_registry,CU_destroy_existing_registry, о которых можно получить дополнительную информацию вдокументации по CUnit.НаборыФункцияCU_pSuite CU_add_suite(const char* strName,CU_InitializeFunc pInit, CU_CleanupFunc pClean)создает новый набор тестов с указанными именем, функциямиустановки и очистки.
Созданный набор добавляется в реестр,соответственно реестр должна быть инициализирован до вызоваданной функции.Имена наборов должны быть уникальны в рамках реестра.Функции инициализации и очистки необязательны, передаются в51виде указателя на функцию без параметров, возвращающую int.Функции должны возвращать 0 в случае успеха. Если набор ненуждается в установке и/или очистке в качестве значениясоответствующего указателя нужно передать NULL.Функция возвращает указатель на созданный набор.
Впоследствие указатель используется для добавления тестов в набор.В случае ошибки возвращается NULL и устанавливается значениекода ошибки, который может быть считан с помощью функций:CU_ErrorCodeconst char*CU_get_error(void);CU_get_error_msg(void);С кодами ошибок, устанавливаемыми функциями CUnit,можно ознакомиться в документации по CUnit.ТестыФункцияCU_pTest CU_add_test(CU_pSuite pSuite, const char*strName, CU_TestFunc pTestFunc)создает новый тест с заданным именем и реализующей его функциейи добавляет его в заданный набор.
Набор pSuite должен быть созданс помощью CU_add_sute. Имена тестов должны быть уникальны врамках набора. Тип CU_testFunc определен как:typedef void (*CU_TestFunc)(void);pTestFunc не может быть NULL. CU_add_test возвращает указательна новый тест. В случае ошибки возвращается NULL иустанавливается код ошибки.Макрос CU_ADD_TESTавтоматически генерируетуникальное имя теста, основываясь на имени функции, реализующейтест, и добавляет тест в заданный набор:#define CU_ADD_TEST(suite, test) (CU_add_test(suite,#test, (CU_TestFunc)test))ПроверкиВ таблице приведены некоторые проверки CUnit:Название макросаCU_ASSERT(int expression)CU_ASSERT_FALSE(value)Контролируемое условиеПроверка на ИСТИНУПроверка на ЛОЖЬ52CU_ASSERT_EQUAL(actual, expected)CU_ASSERT_NOT_EQUAL(actual,expected))CU_ASSERT_PTR_EQUAL(actual,expected)CU_ASSERT_STRING_EQUAL(actual,expected)CU_ASSERT_NSTRING_EQUAL(actual,expected, count)CU_ASSERT_DOUBLE_EQUAL(actual,expected, granularity)Проверка на равенствоПроверка на неравенствоПроверка указателей наравенствоПроверкастрокнаравенствоПроверкапервыхNсимволовстрокнаравенствоПроверкачиселсплавающей точкой наравенствосзаданнойточностьюCUnit предоставляет макросы с суффиксом “FATAL”,например, CU_ASSERT_FATAL, обеспечивающие останов процессатестирования на текущем тесте в случае невыполнения проверки.Запуск тестовБазовый режимCU_ErrorCode CU_basic_run_tests(void)Запуск всех тестов.
Возвращает код первой ошибки, возникшей призапуске тестов.CU_ErrorCode CU_basic_run_suite(CU_pSuite pSuite)Запуск всех тестов заданного набора. Возвращает код первойошибки, возникшей при запуске тестов.CU_ErrorCode CU_basic_run_test(CU_pSuite pSuite, CU_pTestpTest)Запуск заданного теста и заданного набора. Возвращает код первойошибки, возникшей при запуске теста.Интерактивный режимВыбор, запуск наборов и тестов, просмотр результатовпроисходят в интерактивном режиме. Для запуска режима консолинеобходимо вызвать функциюvoid CU_console_run_tests(void)53Получение результатов прохождения тестовconst CU_pRunSummary CU_get_run_summary(void)Возвращает результаты запуска тестов.
Возвращаемое значение –указатель на структуру CU_RunSummary, содержащую статистикузапуска тестов (поля структуры самодокументируемы):typedef struct CU_RunSummary{unsigned int nSuitesRun;unsigned int nSuitesFailed;unsigned int nTestsRun;unsigned int nTestsFailed;unsigned int nAsserts;unsigned int nAssertsFailed;unsigned int nFailureRecords;} CU_RunSummary;typedef CU_Runsummary* CU_pRunSummary;Функцияconst CU_pFailureRecord CU_get_failure_list(void)возвращает информацию о тестах, не пройденных за последнийзапуск (NULL, если все тесты прошли) в виде списка структур,содержащих данные о местоположении теста и не пройденнойпроверке:typedef struct CU_FailureRecord{unsigned int uiLineNumber;char*strFileName;char*strCondition;CU_pTestpTest;CU_pSuitepSuite;struct CU_FailureRecord* pNext;struct CU_FailureRecord* pPrev;} CU_FailureRecord;typedef CU_FailureRecord*CU_pFailureRecord;54Пример использования CUnitРассмотрим функции по работе со множеством чисел(структура Set):#include <stdlib.h>/* Множество */struct _Set{int * data;int size;};typedef struct _Set Set;/* Код успеха */#define SUCCESS 1/* Код неуспеха */#define FAIL 0typedef int Result;/* ИНТЕРФЕЙС МНОЖЕСТВА *//* Проверка вхождения, возвращает 1, если множество содержит элемент,иначе 0 */int contains(Set * set, int elem);/* Вставка, вставляет элемент и возвращает SUCCESS, если исходноемножество не содержит элемент, иначе FAIL */Result insert(Set * set, int elem);/* Удаление, удаляет и возвращает SUCCESS, если исходное множествосодержит элемент, иначе FAIL */Result remove(Set * set, int elem);/* РЕАЛИЗАЦИЯ *//* Двоичный поиск в упорядоченном массиве.
Возвращает индекс (начинаяс 0) найденного элементалибо -1. В случае нескольких вхождений одного и того же элемента,возвращается индекспроизвольного.При отсутствии искомого элемента в массиве через posBeforeвозвращается индекс ближайшегоэлемента, меньшего искомого */int _bsearch (int * array, int len, int elem, int * posBefore){int low = 0, high = len - 1;while(low <= high){int mid = (low + high) / 2;if (elem == array[mid])return mid;else if (elem < array[mid])55high = mid - 1;elselow = mid + 1;}if(NULL != posBefore)*posBefore = high;return -1;}int contains(Set * set, int elem){return indexOf(set, elem) != -1;}int indexOf(Set * set, int elem){return _bsearch(set->data, set->size - 1, elem, NULL);}Result insert(Set * set, int elem){int index, posBefore;index = _bsearch(set->data, set->size, elem, &posBefore);if(index != -1)return FAIL;set->data = realloc(set->data, sizeof(int) * (set->size + 1));memmove(set->data + posBefore + 2, set->data + posBefore + 1,sizeof(int) * (set->size - posBefore - 1));set->data[posBefore + 1] = elem;set->size++;return SUCCESS;}Result remove(Set * set, int elem){int index, posBefore;index = _bsearch(set->data, set->size, elem, &posBefore);if(index == -1)return FAIL;set->data = realloc(set->data, sizeof(int) * (set->size - 1));memmove(set->data + index, set->data + index + 1, sizeof(int) *(set->size - index - 1));set->size--;return SUCCESS;56}Автоматические тесты могут созданы как на функции интерфейсабиблиотеки:void test1(void){Set s = {0};CU_ASSERT_EQUAL(s.size, 0);insert(&s, 3);CU_ASSERT_EQUAL(s.size, 1);insert(&s, 1);CU_ASSERT_EQUAL(s.size, 2);CU_ASSERT_EQUAL(s.data[0], 1);CU_ASSERT_EQUAL(s.data[1], 3);}void test2(void){Set s = {0};CU_ASSERT_EQUAL(insert(&s, 1), SUCCESS);CU_ASSERT_EQUAL(insert(&s, 1), FAIL);}void test3(void){Set s = {0};insert(&s, 1);CU_ASSERT_EQUAL(remove(&s, 2), FAIL);CU_ASSERT_EQUAL(remove(&s, 1), SUCCESS);}, так и на функцию _bsearch, используемую реализацией библиотеки:void test4(){int array[] = {1, 3, 5, 11};int size = sizeof(array) / sizeof(int);int posBefore;57CU_ASSERT_EQUAL(_bsearch(array, size, 4, &posBefore),-1);CU_ASSERT_EQUAL(posBefore, 1);CU_ASSERT_EQUAL(_bsearch(array, size, 19,&posBefore), -1);CU_ASSERT_EQUAL(posBefore, 3);CU_ASSERT_EQUAL(_bsearch(array, size, 5, &posBefore),2);}Следует отметить, что в реальных программах обычно создаетсябольшее число тестов, чем в рассмотренном примере.
Тестовоепокрытие должно по возможности описывать все многообразиеситуаций,вкоторыхотфункциихочетсяожидатьдетерминированный результат. Например, «пустые» параметры,граничные точки, вообще говоря, любые параметры, обладающиесвойствами, прямо или косвенно используемыми реализацией(например, четность/нечетность числа элементов массива в_bsearch). Иногда бывает полезно включить в тестовый набор тесты,проверяющие обработку функцией входных некорректныхпараметров.Пример кода помещения тестов в набор и их автоматическогозапуска:#include <CUnit/Basic.h>int main(){CU_pSuite suite;CU_initialize_registry();suite = CU_add_suite("main_suite", NULL, NULL);CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,test1);test2);test3);test4);CU_basic_run_tests();58CU_cleanup_registry();return CU_get_error();}Данная тестирующая программа, скомпилированная в исполняемыйфайл testrunner в последствии может стать отдельной цельюMakefile:test:testrunnerПример запуска среды интерактивной проверки CUnit:#include <CUnit/Console.h>int main(){CU_pSuite suite;CU_initialize_registry();suite = CU_add_suite("main_suite", NULL, NULL);CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,CU_ADD_TEST(suite,test1);test2);test3);test4);CU_console_run_tests();CU_cleanup_registry();return 0;}Документированиеисходныхиспользованием DoxygenтекстовпрограммсВозвращаясь к примеру функции _bsearch из предыдущегораздела, реализующей бинарный поиск, следует обратить вниманиена тот факт, что имея перед глазами один только прототип этойфункцииint _bsearch (int * array, int len, int elem, int *posBefore)59, сложно догадаться о смысле некоторых параметров, например,параметра posBefore.
Конечно же, можно заглянуть в реализациюфункции, однако это требует дополнительного времени, сил исопряжено с ошибками интерпретации кода. Кроме этого, не во всехслучаях исходный текст реализации доступен программисту.Помочь решить проблему может документирование данной функции– снабжение ее текстом, описывающим семантику параметров ивозвращаемого значения. Документирование, как правило,производится в исходном тексте программы, используяспециальнымобразомразмеченныйкомментарийязыкапрограммирования,расположенныйнепосредственнопередописываемым элементом программы: типом либо функцией.Системы генерации документации позволяют упроститьпроцесс документирования.Основной их задачей являетсяавтоматическоепостроениефайловдокументацииподокументирующимкомментариям.Принимаянавходдокументированные исходные тексты программы, генератордокументации сопоставляет документирующие комментарии сдокументируемыми элементами программы, осуществляет разбор иконтроль корректности разметки и формирует итоговуюдокументацию в одном из популярных текстовых форматов.Кросс-платформенная система генерации документацииDoxygen(http://www.doxygen.org)поддерживаетязыкипрограммирования Си++, Си, Objective-C, Python, Java, IDL, PHP,C#, Fortran, VHDL, D и генерирует документацию на основе набораисходных текстов, содержащих документирующие комментарии встиле Си/Си++.