Как модульно протестировать статическую процедуру обратного вызова, вызываемую из ISR

#c #unit-testing #cmock #ceedling

#c #модульное тестирование #cmock #ceedling

Вопрос:

Я использую ceedling для модульного тестирования приложения на C и пытаюсь достичь высокого охвата ~ 100%.

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

В AppModule.c,

 typedef void( *type_appCallback ) ( void );

static void appCallback( void );
 

Я хочу выполнить модульное тестирование этой функции, и поскольку эта функция является статической, она не будет отображаться в ceedling test_appModule.c.
У меня есть обходной путь для этого определения TEST_STATIC вместо static ,

 #ifdef TEST 
TEST_STATIC
#else
TEST_STATIC static
#endif
 

Но я не большой поклонник этой работы, какие-либо предложения по вышеуказанной проблеме?

Ответ №1:

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

wrap_app_Module.c

 /* include code of static function (.c is intentional, not .h) */
#include "appModule.c"

void wrap_appCallback(void)
{
    appCallback();
}
 

Вместо static функции вы можете вызвать функцию-оболочку в своих тестах.

Ответ №2:

Я сделал что-то похожее на то, что предложил @Bodo выше, используя плагин обратного вызова CMock. Примечание cmockNumCalls является обязательным параметром для функции stub

Производственный код -> setCallback( funcAddress );

Код модульного тестирования -> setCallback_Stub( storeFuncAddress);

Где storeFuncAddress выглядит как

 void storeFuncAddress(
      type_appCallback       appCallbackFn,
      int                    cmockNumCalls)
{
    l_storedCallbackFn = appCallbackFn;
}
 

Когда вызывается версия _Stub, она передает те же параметры зарегистрированной функции обратного вызова, поэтому storeFuncAddress получает тот же адрес функции (который является указателем на статический) и сохраняет его в переменной типа type_appCallback, которую я вызываю l_storedCallbackFn.

Вторая часть — это то, где запускается событие.

Производственный код -> triggerCallback();

Код модульного тестирования -> triggerCallback_Stub( runStoredCallbackFunction );

Где моя функция runStoredCallbackFunction выглядит так

 void runStoredCallbackFunction(
    int                       cmockNumCalls)
{
    (*l_storedCallbackFn)(NULL);
}
 

Надеюсь, это поможет вам или следующему человеку, который столкнется с этим же вопросом.