it-swarm-ru.tech

Модульное тестирование кода C

Этим летом я работал над встроенной системой, написанной прямо на C. Это был существующий проект, который перешла к компании, в которой я работаю. Я привык к написанию модульных тестов в Java с использованием JUnit, но не знал, как лучше написать модульные тесты для существующего кода (который требует рефакторинга), а также для добавления нового кода в систему. ,.

Есть ли способ сделать модульное тестирование простым C-кодом таким же простым, как модульное тестирование Java кода, например, JUnit? Будем весьма благодарны за любые идеи, которые будут относиться конкретно к разработке встраиваемых систем (кросс-компиляция для платформы arm-linux).

812
Paul Osborne

Основой для модульного тестирования в C является Проверка ; список структур модульного тестирования в 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 homepage .

Симпатичных

Простая структура с одним .c и одним .h файлом, который вы перетаскиваете в дерево исходных текстов. Смотрите домашняя страница CuTest .

CppUnit

Основа для модульного тестирования C++; Вы также можете использовать его для тестирования кода C. Он стабилен, активно развивается и имеет графический интерфейс. Основные причины не использовать CppUnit для C: во-первых, он довольно большой, а во-вторых, вы должны писать свои тесты на C++, что означает, что вам нужен компилятор C++. Если это не похоже на проблемы, это, безусловно, стоит рассмотреть, наряду с другими средами модульного тестирования C++. Смотрите домашняя страница CppUnit .

embUnit

embUnit (Embedded Unit) - это еще одна инфраструктура модульного тестирования для встроенных систем. Этот, кажется, заменен AceUnit. домашняя страница встроенного блока .

MinUnit

Минимальный набор макросов и все! Суть в том, чтобы показать, как легко выполнить модульное тестирование вашего кода. Смотрите MinUnit homepage .

Блок для мистера Андо

Реализация CUnit, которая является довольно новой и, видимо, все еще находится на ранней стадии разработки. Смотрите CUnit для главной страницы Mr. Ando .

Этот список последний раз обновлялся в марте 2008 года.

Больше рамок:

CMocka

CMocka - это тестовая среда для C с поддержкой фиктивных объектов. Это просто в использовании и настройке.

Смотрите домашняя страница CMocka .

Критерий

Criterion - это кроссплатформенная инфраструктура модульного тестирования C, поддерживающая автоматическую регистрацию тестов, параметризованные тесты, теории и способная выводить данные в несколько форматов, включая TAP и JUnit XML. Каждый тест выполняется в своем собственном процессе, поэтому при необходимости можно сообщать о сигналах и сбоях.

Смотрите домашняя страница критерия для получения дополнительной информации.

HWUT

HWUT - это общий инструмент модульного тестирования с отличной поддержкой C. Он может помочь создавать Make-файлы, генерировать массивные тестовые примеры, закодированные в минимальных "таблицах итераций", проходить по конечным автоматам, генерировать C-заглушки и многое другое. Общий подход довольно уникален: вердикты основаны на "хороший стандартный вывод/плохой стандартный вывод". Функция сравнения, однако, является гибкой. Таким образом, любой тип сценария может быть использован для проверки. Это может быть применено к любому языку, который может производить стандартный вывод.

Смотрите домашняя страница HWUT .

CGreen

Современный, переносимый, кросс-языковой модуль для тестирования и макетирования C и C++. Он предлагает дополнительную нотацию BDD, библиотеку-макет, возможность запускать ее в одном процессе (для облегчения отладки). Доступен тестовый прогон, который автоматически обнаруживает функции теста. Но вы можете создавать свои собственные программно.

Все эти функции (и многое другое) описаны в руководство CGreen .

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

463
Adam Rosenfield

Лично мне нравится 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, скомпилированного для Linux на архитектуре PowerPC. Это имеет смысл, потому что у вас есть полная оболочка и ОС для сбора ваших результатов. Для менее богатых сред (которые я классифицирую как что-либо без полноценной ОС) вы должны просто собрать и запустить на хосте. Вы должны сделать это в любом случае, чтобы вы могли запускать тесты автоматически как часть сборки.

Я считаю, что тестирование кода на C++, как правило, намного проще из-за того, что код OO, как правило, гораздо менее связан, чем процедурный (конечно, это сильно зависит от стиля кодирования). Также в C++ вы можете использовать приемы, такие как внедрение зависимостей и переопределение методов, чтобы получить швы в код, который инкапсулируется в противном случае.

У Майкла Фезерса есть отличная книга о тестировании устаревшего кода . В одной главе он описывает методы работы с не-OO-кодом, которые я настоятельно рекомендую.

Редактировать : я написал сообщение в блоге о процедурном коде модульного тестирования, с источник доступен на GitHub .

Редактировать : есть новая книга, выпускаемая прагматичными программистами , которая конкретно посвящена модульному тестированию кода C, который Я очень рекомендую .

152
mikelong

Minunit - невероятно простая структура модульного тестирования. Я использую его для модульного тестирования кода микроконтроллера для AVR.

128
Matteo Caprari

В настоящее время я использую среду модульного тестирования CuTest:

http://cutest.sourceforge.net/

Он идеально подходит для встраиваемых систем, поскольку он очень легкий и простой. У меня не было проблем, чтобы заставить его работать на целевой платформе, а также на рабочем столе. В дополнение к написанию модульных тестов все, что требуется, это:

  • файл заголовка включен везде, где вы вызываете подпрограммы CuTest
  • один дополнительный файл 'C' для компиляции/ссылки на изображение
  • некоторый простой код добавлен в main для настройки и вызова модульных тестов - я просто использую это в специальной функции main (), которая компилируется, если во время сборки определен UNITTEST.

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

При некотором разумном использовании внешних блоков "C" {} он также прекрасно поддерживает тестирование C++.

40
Michael Burr

Я говорю почти так же, как ratkok, но если у вас есть встроенный поворот для модульных тестов, то ...

nity - Настоятельно рекомендуемая среда для модульного тестирования C-кода.

Примеры в книге, упомянутой в этой теме TDD для встроенного C , написаны с использованием Unity (и CppUTest).

36
Johan

Возможно, вы также захотите взглянуть на 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();
}
32
Ovid

Существует элегантная среда модульного тестирования для 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: Модульное тестирование с фиктивными объектами в C

cmocka 1.0 была выпущена в феврале 2015 года.

26
asn

Я не стал долго тестировать устаревшее приложение C, прежде чем начал искать способ имитации функций. Мне были нужны насмешки, чтобы изолировать C-файл, который я хочу проверить, от других. Я дал cmock попытку, и я думаю, что приму это.

Cmock сканирует заголовочные файлы и генерирует фиктивные функции на основе найденных им прототипов. Насмешки позволят вам протестировать файл C в полной изоляции. Все, что вам нужно сделать, это связать ваш тестовый файл с макетами вместо ваших реальных объектных файлов.

Еще одним преимуществом cmock является то, что он будет проверять параметры, передаваемые имитируемым функциям, и позволит вам указать, какое возвращаемое значение должно предоставлять mocks. Это очень полезно для проверки различных потоков исполнения в ваших функциях.

Тесты состоят из типичных функций testA (), testB (), в которых вы строите ожидания, вызываете функции для тестирования и проверки утверждений.

Последний шаг - создать бегуна для ваших тестов с единством. Cmock связан со структурой тестирования единства. Unity так же легко изучить, как и любой другой фреймворк.

Стоит попробовать и довольно легко понять:

http://sourceforge.net/apps/trac/cmock/wiki

Обновление 1

Еще одна структура, которую я исследую, - это Cmockery.

http://code.google.com/p/cmockery/

Это чистый C-фреймворк, поддерживающий модульное тестирование и макетирование. Он не зависит от Ruby (в отличие от Cmock) и очень мало зависит от внешних библиотек.

Для настройки макетов требуется немного больше ручной работы, потому что он не генерирует код. Это не представляет большой работы для существующего проекта, так как прототипы не сильно изменятся: если у вас есть макеты, вам не нужно будет их менять некоторое время (это мой случай). Дополнительный набор текста обеспечивает полный контроль над макетами. Если есть что-то, что вам не нравится, вы просто меняете свой макет.

Нет необходимости в специальном тесте. Вам нужно только создать массив тестов и передать его в функцию run_tests. Здесь тоже немного больше ручной работы, но мне определенно нравится идея автономной автономной структуры.

Кроме того, он содержит некоторые изящные трюки C, которых я не знал.

В целом Cmockery нужно немного больше понимать, что такое макеты, чтобы начать. Примеры должны помочь вам преодолеть это. Похоже, что он может сделать работу с более простой механикой.

20
Philippe A.

Как новичок в C, я обнаружил, что слайды, называемые Разработка, управляемая тестами в C , очень полезны. По сути, он использует стандартную assert() вместе с && для доставки сообщения без каких-либо внешних зависимостей. Если кто-то привык к фреймворку полного стека, это, вероятно, не сработает :)

15
chelmertz

Я не использую фреймворк, я просто использую autotools "check" target support. Реализуйте "main" и используйте assert (s).

Мой тестовый каталог Makefile.am выглядит так:

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
12
navicore

Существует CUnit

И Embedded Unit является структурой модульного тестирования для Embedded C System. Его дизайн был скопирован с JUnit и CUnit и более, а затем несколько адаптирован для Embedded C System. Встроенный модуль не требует стандартных библиотек. Все объекты размещены в постоянной области.

И Tessy автоматизирует модульное тестирование встроенного программного обеспечения.

12
prakash

Мы написали 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

У него тоже красивые цвета.

12
Tuplanolla

В книге Майкла Фезера "Эффективная работа с устаревшим кодом" представлено множество методов, специфичных для модульного тестирования во время разработки на Си.

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

11
Frank Schwieterman

CppUTest - Настоятельно рекомендуемая среда для модульного тестирования C-кода.

Примеры в книге, упомянутой в этой теме TDD для встроенного C , написаны с использованием CppUTest.

7
ratkok

кроме моего очевидного уклона

http://code.google.com/p/seatest/

хороший простой способ модульного тестирования C-кода. подражает xUnit

6
Keith Nicholas

Я использую CxxTest для встроенной среды c/c ++ (прежде всего C++).

Я предпочитаю CxxTest, потому что у него есть скрипт на Perl/python для сборки тестового прогона. После небольшого уклона, чтобы его настроить (еще меньше, так как вам не нужно писать тестовый прогон), его довольно легко использовать (включает примеры и полезную документацию). Большая часть работы заключалась в настройке "аппаратного обеспечения", к которому обращается код, чтобы я мог эффективно тестировать модуль/модуль. После этого легко добавить новые тестовые случаи.

Как упоминалось ранее, это среда модульного тестирования C/C++. Так что вам понадобится компилятор C++.

Руководство пользователя CxxTestCxxTest Wiki

6
Zing-

Прочитав Minunit, я подумал, что лучше использовать тестовый макрос в assert, который я часто использую, например, метод защитной программы. Поэтому я использовал ту же идею Minunit, смешанную со стандартным assert. Вы можете увидеть мой фреймворк (хорошее имя может быть NoMinunit) в блог k0ga

5
Roberto Vargas Caballero

У Google отличная система тестирования. https://github.com/google/googletest/blob/master/googletest/docs/primer.md

И да, насколько я вижу, он будет работать с простым C, то есть не требует функций C++ (может потребоваться компилятор C++, не уверен).

4
Paweł Hajdan
4
Landon Kuhn

Cmockery - это недавно запущенный проект, который состоит из очень простой в использовании библиотеки C для написания модульных тестов.

4
Alejandro Bologna

Сначала посмотрите здесь: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C

У моей компании есть библиотека C, которую используют наши клиенты. Мы используем CxxTest (библиотека модульных тестов C++) для тестирования кода. CppUnit также будет работать. Если вы застряли в C, я бы порекомендовал RCUNIT (но CUnit тоже хорош).

3
Kevin

попробуйте lcut! - http://code.google.com/p/lcut

2
Tony Bai

API Sanity Checker - тестовая среда для библиотек C/C++:

Автоматический генератор базовых модульных тестов для общей библиотеки C/C++. Он способен генерировать разумные (в большинстве, но, к сожалению, не во всех случаях) входные данные для параметров и составлять простые ("нормальные" или "поверхностные") тестовые случаи для каждой функции в API посредством анализа объявлений в заголовке файлы.

Качество генерируемых тестов позволяет проверять отсутствие критических ошибок в простых случаях использования. Инструмент может создавать и выполнять сгенерированные тесты и обнаруживать сбои (segfaults), прерывания, все виды излучаемых сигналов, ненулевой код возврата программы и зависание программы.

Примеры:

2
linuxbuild

Я использовал RCUNIT , чтобы выполнить некоторое модульное тестирование встроенного кода на ПК перед тестированием на целевой. Хорошая абстракция аппаратного интерфейса важна, иначе регистры с порядком байтов и отображением памяти убьют вас.

2
Gerhard

Если вы знакомы с JUnit, то я рекомендую CppUnit. http://cppunit.sourceforge.net/cppunit-wiki

Это предполагает, что у вас есть компилятор c ++ для выполнения модульных тестов. если нет, то я должен согласиться с Адамом Розенфилдом, что чек - это то, что вы хотите.

2
Kwondri

LibU ( http://koanlogic.com/lib ) имеет модуль модульного тестирования, который позволяет явно определять зависимости набора тестов/случаев, изоляцию тестов, параллельное выполнение и настраиваемый форматер отчетов (по умолчанию это xml и txt). ).

Библиотека имеет лицензию BSD и содержит много других полезных модулей - сети, отладки, часто используемых структур данных, конфигурации и т.д. - если они понадобятся вам в ваших проектах ...

1
bongo

Я удивлен, что никто не упомянул Cutter (http://cutter.sourceforge.net/) Вы можете протестировать C и C++, он легко интегрируется с autotools и имеет действительно хороший учебник.

1
Kris

Один из способов - разработка кода модульного теста с использованием инфраструктуры C++ xUnit (и компилятора C++), при этом исходный код целевой системы сохраняется в виде модулей C.

Убедитесь, что вы регулярно компилируете исходный код C под свой кросс-компилятор, автоматически с вашими модульными тестами, если это возможно.

1
quamrana

Если вы все еще в поисках тестовых сред, CUnitWin32 - это то, что нужно для платформы Win32/NT.

Это решает одну фундаментальную проблему, с которой я столкнулся в других средах тестирования. А именно глобальные/статические переменные находятся в детерминированном состоянии, потому что каждый тест выполняется как отдельный процесс.

0
Dushara

Если вы ориентируетесь на платформы Win32 или режим ядра NT, вам следует взглянуть на cfix .

0
Johannes Passing

Я только что написал Libcut из-за разочарования в существующих библиотеках модульного тестирования Си. Он имеет автоматическое определение типа примитивов (нет необходимости в 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, хотя.

0
kirbyfan64sos