Ответов (12)12
Если вы находитесь в среде Unix вы можете включить в тест файл дополнительный заголовок yourheader_static.h
с декларациями ваших статических функций и перевести OBJ файл code_under_test.o
через objdump --globalize-symbols=syms_name_file
глобализовать локальные символы. Они будут видны как нестатические функции.
Это можно сделать двумя способами.
Включите исходный файл c в исходный файл модульного тестирования, чтобы статический метод теперь находился в области действия исходного файла модульного тестирования и мог быть вызван.
Сделайте трюк:
#define static
в заголовке исходного файла модульного тестирования.
Он преобразует ключевое слово static
в "ничего" или, я могу сказать, удаляет его static
из исходного кода c.
В некоторых инструментах модульного тестирования мы можем использовать опцию конфигурации «препроцессор», чтобы сделать этот трюк, просто введите конфигурацию:
static=
Инструмент преобразует все static
ключевые слова в "ничего"
Но я должен сказать, что использование этих способов приводит к тому, что static
метод (или переменная) теряет свое конкретное значение.
#define static
Это очень плохая идея. Если у вас есть переменная, объявленная локальной для функции, это меняет поведение функции. Пример:
static int func(int data)
{
static int count = 0;
count += data;
return count;
}
Вы можете вызвать функцию из модульного теста, поскольку функция func () будет экспортирована, однако базовая функциональность кода будет изменена.
--курт
Если вы используете Ceedling и пытаетесь использовать метод #include «code_under_test.c», тестовая сборка завершится неудачно, потому что она автоматически попытается создать «code_under_test.c» один раз при #included, а также потому, что это цель теста .
Мне удалось обойти это путем небольшой модификации кода code_under_test.c и нескольких других изменений. Оберните весь файл code_under_test.c этой проверкой:
#if defined(BUILD)
...
#endif // defined(BUILD)
Добавьте это в свой тестовый жгут:
#define BUILD
#include "code_under_test.c"
Добавьте BUILD
определение в свой Makefile или файл конфигурации проекта:
# Makefile example
..
CFLAGS += -DBUILD
..
Теперь ваш файл будет собран из вашей среды и при включении из вашей тестовой среды. Ceedling теперь не сможет построить файл во второй раз (убедитесь, что ваш файл project.yml НЕ определяет BUILD).
Все предложенные выше ответы (за исключением нескольких) предполагают условную компиляцию, которая требует изменения исходного кода. Таким образом, это не должно быть проблемой, это просто добавит беспорядка (только для тестирования). Скорее можно сделать что-то вроде этого.
Скажите, что ваша функция для тестирования
static int foo(int);
Вы создаете другой файл заголовка с именем testing_headers.h, который будет иметь содержимое -
static int foo(int);
int foo_wrapper(int a) {
return foo(a);
}
Теперь при компиляции файла c для тестирования вы можете принудительно включить этот заголовок из параметров компилятора.
Для clang и gcc флаг есть --include
. Для компилятора Microsoft C это так /FI
.
Это потребует абсолютно нулевых изменений в вашем файле c, и вы сможете написать нестатическую оболочку для своей функции.
Если вам не нужна нестатическая оболочка, вы также можете создать нестатический глобальный указатель на функцию, инициализированный значением foo.
Затем вы можете вызвать функцию, используя этот глобальный указатель на функцию.
Просто чтобы добавить к принятому ответу Джонатана Леффлера и подробно рассказать о других упоминаниях функции-оболочки:
- Создайте тестовый исходный файл, как в test_wrapper_foo.c, где foo.c - это оригинал.
- В test_wrapper_foo.c:
#include "foo.c" // Prototype int test_wrapper_foo(); // wrapper function int test_wrapper_foo() { // static function to test return foo(); }
Предполагая, что статическая функция foo в foo.c имеет прототип: int foo (void);
создайте test_wrapper_foo.c через свой make-файл вместо foo.c (обратите внимание, что это не нарушит никаких зависимостей от функций в foo.c другими внешними функциями)
В сценарии модульного тестирования вызовите test_wrapper_foo () вместо foo ().
При таком подходе исходный исходный код остается неизменным, но вы получаете доступ к функции из вашей тестовой среды.
Нет - вы не можете напрямую протестировать статическую функцию, не изменив хотя бы немного источник (это определение static в C - то, что он не может быть вызван из функции в другом файле).
Вы можете создать отдельную функцию в тестовом файле, которая просто вызывает статическую функцию?
Например:
//Your fn to test
static int foo(int bar)
{
int retVal;
//do something
return retVal;
}
//Wrapper fn
int test_foo(int bar)
{
return foo(bar);
}
Обычно мы не тестируем наши статические функции напрямую, а скорее гарантируем, что выполняемая ими логика адекватно протестирована различными тестами вызывающей функции.
Для модульных тестов у нас фактически есть тестовый код в самом исходном файле, и мы условно компилируем его при тестировании. Это дает модульным тестам полный доступ ко всем функциям и переменным уровня файла (статическим или другим).
Сами модульные тесты не статичны - это позволяет нам вызывать модульные тесты из одной супертестовой программы, которая тестирует все модули компиляции.
Когда мы отправляем код, мы условно компилируем модульные тесты, но на самом деле в этом нет необходимости (если вы хотите быть уверены, что отправляете точно такой же код, который вы тестировали).
Мы всегда считали бесценным наличие модульных тестов в том же месте, что и код, который вы тестируете, поскольку это делает более очевидным, что вам нужно обновлять тесты, если и когда код изменится.
Не могли бы вы дать дополнительную информацию о том, почему вы не можете вызвать функцию?
Он недоступен, потому что он является частным для файла .c? Если это так, лучше всего использовать условную компиляцию, которая позволяет получить доступ к функции, чтобы другие единицы компиляции могли получить к ней доступ. Например
SomeHeaderSomewher.h
#if UNIT_TEST
#define unit_static
#else
#define unit_static static
#endif
Foo.h
#if UNIT_TEST
void some_method
#endif
Foo.cpp
unit_static void some_method() ...
статические функции по сути являются вспомогательными функциями для общедоступных (т. е. открытых) функций. Итак, IMO, ваши модульные тесты должны вызывать общедоступный интерфейс с входами, которые проверяют все пути в статической функции.
Выходные данные (возвращаемые значения / побочные эффекты) публичной функции следует использовать для проверки эффекта статики.
Это означает, что вам нужны соответствующие заглушки, чтобы «уловить» эти побочные эффекты. (например, если функция вызывает файловый ввод-вывод, вам необходимо предоставить заглушки, чтобы переопределить эти файловые функции ввода-вывода lib). Лучший способ сделать это - сделать каждый набор тестов отдельным проектом / исполняемым файлом и избегать ссылок на какие-либо внешние функции библиотеки. Вы можете издеваться даже над функциями C, но это того не стоит.
В любом случае, это тот подход, который я использовал до сих пор, и он работает для меня. Удачи