Я работал над встроенной системой этим летом, написанным на прямой C. Это был уже существующий проект, в котором я работал. Я довольно привык к написанию модульных тестов на Java с помощью JUnit, но был в недоумении, как лучший способ писать модульные тесты для существующего кода (который нуждался в рефакторинге), а также новый код, добавленный в систему.
Есть ли способ сделать unit тест простым C-кодом столь же простым, как и модульное тестирование кода Java, например, JUnit? Было бы с благодарностью оценено любое понимание, которое будет применяться специально для встроенной разработки (кросс-компиляция на платформу arm-linux).
Одним из основ модульного тестирования в Си является Check; список фреймворков для модульного тестирования в C можно найти здесь и воспроизвести ниже. В зависимости от того, сколько стандартных библиотечных функций имеет ваша среда выполнения, вы можете или не сможете использовать одну из них.
AceUnit
AceUnit (Advanced C и Embedded Unit) позиционирует себя как удобную среду модульного тестирования кода C. Он пытается имитировать JUnit 4.x и включает в себя возможности, подобные отражению. AceUnit может использоваться в средах с ограниченными ресурсами, например, при разработке встроенного программного обеспечения, и, что важно, он отлично работает в средах, где вы не можете включить один стандартный заголовочный файл и не можете вызвать одну стандартную функцию C из библиотек ANSI/ISO C. У этого также есть порт Windows. Он не использует вилки для захвата сигналов, хотя авторы проявили интерес к добавлению такой функции. Смотрите домашнюю страницу AceUnit.
GNU Autounit
Во многом по той же схеме, что и Check, включая разветвление для запуска модульных тестов в отдельном адресном пространстве (фактически, первоначальный автор Check позаимствовал идею у GNU Autounit). GNU Autounit широко использует GLib, а это означает, что для линковки и тому подобного необходимы специальные опции, но это не может быть большой проблемой для вас, особенно если вы уже используете GTK или GLib. Смотрите домашнюю страницу GNU Autounit.
Куните
Также использует GLib, но не разветвляется для защиты адресного пространства модульных тестов.
Куните
Стандартный C, с планами по реализации Win32 GUI. В настоящее время не разветвляется или иным образом не защищает адресное пространство модульных тестов. В начале разработки. Смотрите домашнюю страницу CUnit.
симпатичных
Простая структура с одним .c и одним .h файлом, который вы перетаскиваете в дерево исходных текстов. Смотрите домашнюю страницу CuTest.
CppUnit
Основная система модульного тестирования для C++; Вы также можете использовать его для тестирования кода C. Он стабилен, активно развивается и имеет графический интерфейс. Основные причины не использовать CppUnit для C: во-первых, он довольно большой, а во-вторых, вы должны написать свои тесты в C++, что означает, что вам нужен компилятор C++. Если это не звучит как проблемы, это определенно стоит рассмотреть, наряду с другими C++ модульными системами тестирования. Смотрите домашнюю страницу CppUnit.
embUnit
embUnit (Embedded Unit) - это еще одна инфраструктура модульного тестирования для встроенных систем. Этот, кажется, заменен AceUnit. Домашняя страница встраиваемого блока.
MinUnit
Минимальный набор макросов и все! Суть в том, чтобы показать, как легко выполнить модульное тестирование вашего кода. Смотрите домашнюю страницу MinUnit.
Блок для мистера Андо
Реализация CUnit, которая является довольно новой и, видимо, все еще находится на ранней стадии разработки. Смотрите CUnit для г-на Андо на домашней странице.
Этот список последний раз обновлялся в марте 2008 года.
CMocka - это тестовая среда для C с поддержкой фиктивных объектов. Это простой в использовании и настройке.
Смотрите домашнюю страницу CMocka.
Criterion - это кроссплатформенная инфраструктура модульного тестирования C, поддерживающая автоматическую регистрацию тестов, параметризованные тесты, теории и способная выводить данные в несколько форматов, включая TAP и JUnit XML. Каждый тест выполняется в своем собственном процессе, поэтому о сигналах и сбоях можно сообщать или тестировать при необходимости.
Смотрите домашнюю страницу Критерий для получения дополнительной информации.
HWUT - это общий инструмент модульного тестирования с отличной поддержкой C. Он может помочь в создании Make файлов, генерации массивных тестовых случаев, закодированных в минимальных "таблицах итераций", прохождении по конечным автоматам, генерации C-заглушек и многого другого. Общий подход довольно уникален: вердикты основаны на "хорошем stdout/плохом stdout". Функция сравнения, однако, является гибкой. Таким образом, любой тип сценария может быть использован для проверки. Это может быть применено к любому языку, который может производить стандартный вывод.
Смотрите домашнюю страницу HWUT.
Современная, переносимая, мультиязычная модульная система тестирования и моделирования для C и C++. Он предлагает дополнительную нотацию BDD, библиотеку-макет, возможность запускать ее в одном процессе (для облегчения отладки). Доступен тестовый бегун, который автоматически обнаруживает функции теста. Но вы можете создавать свои собственные программно.
Все эти функции (и многое другое) описаны в руководстве CGreen.
Википедия дает подробный список платформ для модульного тестирования в разделе " Список платформ для модульного тестирования": C
Лично мне нравится Google Test framework.
Настоящая сложность тестирования кода C ломает зависимости от внешних модулей, поэтому вы можете изолировать код в единицах. Это может быть особенно проблематично, когда вы пытаетесь получить тесты по устаревшему коду. В этом случае я часто использую компоновщик для использования функций заглушек в тестах.
Это то, о чем люди говорят, когда говорят о швах. В C ваш единственный вариант - использовать предварительный процессор или компоновщик для извлечения зависимостей.
Типичный набор тестов в одном из моих проектов на C может выглядеть следующим образом:
#include "myimplementationfile.c"
#include <gtest/gtest.h>
// Mock out external dependency on mylogger.o
void Logger_log(...){}
TEST(FactorialTest, Zero) {
EXPECT_EQ(1, Factorial(0));
}
Обратите внимание, что вы фактически включаете файл C, а не файл заголовка. Это дает преимущество доступа ко всем статическим элементам данных. Здесь я издеваюсь над своим регистратором (который может быть в logger.o и дает пустую реализацию. Это означает, что тестовый файл компилируется и связывается независимо от остальной базы кода и выполняется изолированно.
Что касается кросс-компиляции кода, для этого вам нужны хорошие объекты для цели. Я сделал это с помощью googletest cross, скомпилированного в Linux на архитектуре PowerPC. Это имеет смысл, потому что у вас есть полная оболочка и os для сбора ваших результатов. Для менее богатых сред (которые я классифицирую как угодно без полной ОС) вы должны просто создавать и запускать на хосте. Вы должны сделать это в любом случае, чтобы вы могли автоматически запускать тесты как часть сборки.
Я нахожу тестирование кода на С++, как правило, намного проще из-за того, что код OO в целом гораздо менее связан с процедурным (конечно, это сильно зависит от стиля кодирования). Также в С++ вы можете использовать трюки, такие как инъекция зависимостей и метод переопределения, чтобы получить швы в код, который иначе инкапсулирован.
Michael Feathers имеет . В одной главе он описывает методы работы с кодом, отличным от OO, который я очень рекомендую.
Изменить. Я написал сообщение о процедуре модульного тестирования с источник, доступный на GitHub.
Изменить. Я очень рекомендую.
Minunit - невероятно простая модульная система тестирования. Я использую его для unit test c кода микроконтроллера для avr.
В настоящее время я использую каркас CuTest unit test:
http://cutest.sourceforge.net/
Он идеален для встроенных систем, поскольку он очень легкий и простой. У меня не было проблем с его работой на целевой платформе, а также на рабочем столе. В дополнение к написанию модульных тестов требуется все:
Система должна поддерживать кучу и некоторые функции stdio (которые не все встроенные системы). Но код достаточно прост, что вы, вероятно, могли бы работать в альтернативах этим требованиям, если ваша платформа их не имеет.
С некоторым разумным использованием блоков extern "C" {} он также поддерживает тестирование С++ просто отлично.
Я говорю почти так же, как ratkok, но если у вас есть встроенный твист для модульных тестов, тогда...
Unity - Очень рекомендуемая основа для модульного тестирования кода C.
Примеры в книге, которые упоминаются в этом потоке TDD для встроенного C, написаны с использованием Unity (и CppUTest).
Вы также можете взглянуть на libtap, структуру тестирования C, которая выводит протокол Test Anything Protocol (TAP) и, таким образом, хорошо интегрируется с различными инструментами для этой технологии. Он в основном используется в динамическом языковом мире, но он прост в использовании и становится очень популярным.
Пример:
#include <tap.h>
int main () {
plan(5);
ok(3 == 3);
is("fnord", "eek", "two different strings not that way?");
ok(3 <= 8732, "%d <= %d", 3, 8732);
like("fnord", "f(yes|no)r*[a-f]$");
cmp_ok(3, ">=", 10);
done_testing();
}
ok(TESTING==IsSimple(), "libtap is super easy to use")
Существует элегантная модульная платформа тестирования для C с поддержкой макетных объектов под названием cmocka. Он требует только стандартную библиотеку C, работает на ряде вычислительных платформ (включая встроенные) и с разными компиляторами.
Он также поддерживает различные форматы вывода сообщений, такие как Subunit, Test Anything Protocol и jUnit XML-отчеты.
cmocka был создан для работы на встроенных платформах, а также имеет поддержку Windows.
Простой тест выглядит следующим образом:
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
(void) state; /* unused */
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(null_test_success),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
API полностью документирован, и несколько примеров являются частью исходного кода.
Чтобы начать работу с cmocka, вы должны прочитать статью на LWN.net: Модульное тестирование с помощью mock-объектов в C
cmocka 1.0 был выпущен в феврале 2015 года.
Я не прошел долгий процесс тестирования устаревшего приложения C, прежде чем начал искать способ издеваться над функциями. Мне нужно было издеваться над тем, чтобы изолировать файл C, который я хочу проверить у других. Я дал попытку, и я думаю, что смогу принять ее.
Cmock сканирует файлы заголовков и генерирует макетные функции на основе найденных им прототипов. Mocks позволит вам протестировать файл C в идеальной изоляции. Все, что вам нужно сделать, это связать ваш тестовый файл с mocks вместо ваших реальных объектных файлов.
Другим преимуществом cmock является то, что он будет проверять параметры, переданные на издеваемые функции, и он позволит вам указать, какое возвращаемое значение должны предоставить mocks. Это очень полезно для тестирования различных потоков выполнения в ваших функциях.
Тесты состоят из типичных функций testA(), testB(), в которых вы строите ожидания, вызываете функции для проверки и проверки утверждений.
Последний шаг - создать бегун для ваших тестов с единством. Cmock привязан к рамке проверки единства. Unity так же легко узнать, как и любая другая инфраструктура unit test.
Хорошо стоит попробовать и довольно легко понять:
http://sourceforge.net/apps/trac/cmock/wiki
Обновление 1
Другая структура, которую я изучаю, - это Cmockery.
http://code.google.com/p/cmockery/
Это чистая C-платформа, поддерживающая модульное тестирование и издевательство. Он не имеет никакого отношения к ruby (вопреки Cmock), и он очень мало зависит от внешних libs.
Для настройки mocks требуется немного более ручная работа, потому что она не генерирует код. Это не представляет большой работы для существующего проекта, так как прототипы не будут сильно меняться: если у вас есть свои макеты, вам не нужно будет их менять некоторое время (это мой случай). Дополнительная набивка обеспечивает полный контроль над mock. Если вам что-то не нравится, вы просто меняете свой макет.
Нет необходимости в специальном тестировщике. Вам нужно только создать массив тестов и передать его функции run_tests. Здесь немного больше ручной работы, но мне определенно нравится идея автономной автономной структуры.
Плюс он содержит некоторые изящные трюки, которые я не знал.
В целом Cmockery требует немного большего понимания макетов для начала. Примеры помогут вам преодолеть это. Похоже, что он может справиться с более простой механикой.
Как новичок C, я нашел слайды под названием Test driven development в C очень полезными. В принципе, он использует стандартный assert()
вместе с &&
для доставки сообщения без каких-либо внешних зависимостей. Если кто-то используется для полной проверки стека, это, вероятно, не будет делать:)
Мы писали CHEAT (размещались на GitHub) для удобства использования и переносимости.
Он не имеет зависимостей и не требует установки или конфигурации. Требуется только файл заголовка и тестовый пример.
#include <cheat.h>
CHEAT_TEST(mathematics_still_work,
cheat_assert(2 + 2 == 4);
cheat_assert_not(2 + 2 == 5);
)
Тесты компилируются в исполняемый файл, который заботится о запуске тестов и сообщает об их результатах.
$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS
У него тоже красивые цвета.
Существует CUnit
И Встроенный модуль - это модульная система тестирования для системы Embedded C. Его дизайн был скопирован с JUnit и CUnit и более, а затем немного адаптирован для Embedded C System. Embedded Unit не требует std C libs. Все объекты выделены для константной области.
И Tessy автоматизирует модульное тестирование встроенного программного обеспечения.
embunit
и был разочарован этим.
Книга Майкла Пера "Эффективно работающая с устаревшим кодом" представляет множество методов, специфичных для модульного тестирования во время разработки C.
Существуют методы, связанные с инъекцией зависимостей, которые специфичны для C, которые я больше нигде не видел.
Я не использую фреймворк, я просто использую autotools "check" target support. Внесите "основные" и используйте assert (s).
Мой тестовый файл Makefile.am(s) выглядит так:
check_PROGRAMS = test_oe_amqp
test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static
TESTS = test_oe_amqp
CppUTest - Очень рекомендуемая структура для модульного тестирования кода C.
Примеры в книге, которые упоминаются в этом потоке TDD для встроенного C, записываются с использованием CppUTest.
кроме моего очевидного смещения
http://code.google.com/p/seatest/
- хороший простой способ для кода unit test C. имитирует xUnit
Я использую CxxTest для встроенной среды c/С++ (прежде всего С++).
Я предпочитаю CxxTest, потому что у него есть perl/python script, чтобы создать тестовый бегун. После небольшого наклона, чтобы настроить его (поменьше, так как вам не нужно писать тест-бегун), он довольно прост в использовании (включает образцы и полезную документацию). Большая часть работы заключалась в настройке "аппаратного обеспечения" доступа к коду, чтобы я мог эффективно тестировать модуль/модуль. После этого легко добавить новые unit test случаи.
Как уже упоминалось ранее, это C/С++ unit test. Поэтому вам понадобится компилятор С++.
Прочитав Minunit, я подумал, что лучший способ - это основа теста в макросах assert, который я использую много, как технику защитной программы. Поэтому я использовал ту же идею, что и Minunit, смешанный со стандартным утверждением. Вы можете увидеть мою фреймворк (хорошее имя может быть NoMinunit) в k0ga blog
Cmockery - это недавно запущенный проект, который состоит из очень простой в использовании библиотеки C для написания модульных тестов.
cmockery на http://code.google.com/p/cmockery/
У Google отличная система тестирования. https://github.com/google/googletest/blob/master/googletest/docs/primer.md
И да, насколько я вижу, он будет работать с простым C, то есть не требует функций C++ (может потребоваться компилятор C++, не уверен).
Во-первых, смотрите здесь: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C
В моей компании есть библиотека C, которую используют наши клиенты. Мы используем CxxTest (библиотека С++ unit test) для проверки кода. CppUnit также будет работать. Если вы застряли на C, я бы рекомендовал RCUNIT (но CUnit тоже хорош).
API Sanity Checker - тестовая среда для библиотек C/С++:
Автоматический генератор базовых модульных тестов для общей библиотеки C/С++. Он способен генерировать разумные (в большинстве, но, к сожалению, не во всех случаях) входные данные для параметров, и составлять простые ( "здравомыслящие" или "мелкие" -качества) тестовые примеры для каждой функции в API посредством анализа объявлений в заголовке файлы.
Качество сгенерированных тестов позволяет проверить отсутствие критических ошибок в простых случаях использования. Инструмент способен создавать и выполнять сгенерированные тесты и обнаруживать сбои (segfaults), прерывания, все виды излучаемых сигналов, ненулевой код возврата программы и зависание программы.
Примеры:
попробуйте lcut! - http://code.google.com/p/lcut
Я использовал RCUNIT для выполнения некоторых модульных тестов для встроенного кода на ПК перед тестированием на цель. Хорошая абстракция аппаратного интерфейса важна, чтобы другие конечные элементы и регистры с отображением памяти собирались убить вас.
Если вы знакомы с JUnit, я рекомендую CppUnit. http://cppunit.sourceforge.net/cppunit-wiki
Это предполагает, что у вас есть компилятор С++ для выполнения модульных тестов. если нет, то я должен согласиться с Адамом Розенфилдом, что проверка - это то, что вы хотите.
Я удивлен, что никто не упомянул Cutter (http://cutter.sourceforge.net/) Вы можете протестировать C и С++, он легко интегрируется с autotools и имеет действительно хороший учебник.
LibU (http://koanlogic.com/libu) имеет модуль unit test, который допускает явные зависимости набора тестов/случаев, тестовую изоляцию, параллельное выполнение и настраиваемый форматировщик отчетов (форматы по умолчанию - xml и txt).
Библиотека BSD лицензирована и содержит множество других полезных модулей - создание сетей, отладка, часто используемые структуры данных, конфигурация и т.д. - если они вам понадобятся в ваших проектах...
Один из способов использования - разработать код unit test с помощью С++ xUnit framework (и компилятора С++), сохраняя при этом источник целевой системы как C-модули.
Удостоверьтесь, что вы регулярно компилируете свой источник C под своим кросс-компилятором, автоматически с помощью ваших модульных тестов, если это возможно.
Я просто написал Libcut из-за разочарования существующими библиотеками тестирования модулей C. Он имеет автоматическое строковое кодирование примитивов (нет необходимости в test_eq_int, test_eq_long, test_eq_short и т.д.), Только два разных набора для примитивов и строк) и состоит из одного файла заголовка. Вот краткий пример:
#include <libcut.h>
LIBCUT_TEST(test_abc) {
LIBCUT_TEST_EQ(1, 1);
LIBCUT_TEST_NE(1, 0);
LIBCUT_TEST_STREQ("abc", "abc");
LIBCUT_TEST_STRNE("abc", "def");
}
LIBCUT_MAIN(test_abc);
Он работает только с C11.
Если вы все еще находитесь в поиске тестовых фреймворков, CUnitWin32 является одним для платформы Win32/NT.
Это решает одну фундаментальную проблему, с которой я столкнулся с другими платформами тестирования. А именно глобальные/статические переменные находятся в детерминированном состоянии, потому что каждый тест выполняется как отдельный процесс.
Если вы ориентируетесь на платформы Win32 или режим ядра NT, вы должны взглянуть на cfix.