Как заменить функцию time () для тестирования производственной библиотеки? - PullRequest
1 голос
/ 11 января 2011

Я хочу написать тесты черного ящика для моей библиотеки C, которая использует стандартные функции времени C (time (), localtime (), gmtime () и т. Д.) Для использования временных меток в своих выходных данных.Выходные данные закодированы, поэтому мне нужно заменить эти функции времени на некоторые тестовые макеты или «бэкдор», чтобы я мог контролировать значение, которое моя библиотека получает из функции time () вместо текущего системного времени, чтобы я мог правильно писать проверки в своих тестах.

Каков наилучший подход для достижения этой цели?Могу ли я иметь такую ​​поддержку в рабочей библиотеке (возможно, с какой-нибудь ручкой?) Или мне следует скомпилировать мою библиотеку в 2 формах: для производства с функциями реального времени () и для тестирования с моими собственными контролируемыми функциями времени ()?

Я интересуюсь кроссплатформенным решением, поэтому такие уловки, как LD_PRELOAD, не являются для меня решением.

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

Ответы [ 3 ]

2 голосов
/ 11 января 2011

То, как я делал это в прошлом для проекта встроенного Си, заключалось в создании двух проектов / конфигураций.
Одна конфигурация была для производственной среды, содержащей весь производственный код (включая зависимости), а другая была для модульного тестирования и содержала драйвер тестирования и все макеты. Две конфигурации совместно использовали источники кода для тестирования.
В среде модульного тестирования я только что связался с имитацией или подделкой всех внешних функций, необходимых для тестируемого кода.

Существует несколько способов связать проверяемый код с необходимыми им мобами:

  • Вы просто предоставляете объектные файлы с макетами компоновщику. Большинство компоновщиков сначала используют имена, найденные в указанных объектных файлах, пытаясь разрешить их с помощью имен из библиотек. Некоторые компоновщики соблюдают порядок, в котором объектные файлы и библиотеки указываются в командной строке, поэтому в этих случаях вы должны убедиться, что макеты указаны перед библиотекой (если вы вообще указали библиотеку).
    Для функций из стандартной библиотеки C это технически вызывает неопределенное поведение, но в большинстве случаев хорошо работает даже для этих функций.
  • Вы создаете набор макросов-обёрток, которые вы можете переключать с помощью определения. Например:

    #ifdef UNIT_TEST
      #define my_time time_mock
    #else
      #define my_time time
    #endif
    
  • Вы создаете набор функций-оболочек (реализованных в другом исходном файле) и предоставляете имитации этих функций. Это имеет небольшой недостаток, заключающийся в том, что эти функции не могут быть проверены модулем без использования одного из методов предыдущих пунктов.

Обновление: Даже если ваш производственный код помещается в библиотеку, конфигурация модульного теста должна создавать (один или несколько) исполняемых файлов.
Код модульного теста не следует включать в производственную библиотеку (хотя вы можете рассмотреть возможность его включения в исходный дистрибутив), поскольку он добавляет только дополнительный багаж с возможностью вызвать ошибки. Хотели бы вы, чтобы один из ваших клиентов случайно переключил библиотеку в режим модульного тестирования и начал жаловаться, что она сломана?

1 голос
/ 11 января 2011

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

Я думаю, это действительно зависит.

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

Поскольку вам никогда не понадобится эта функция в рабочей среде, я бы рекомендовал сделать ее элементом конфигурации во время компиляции, чтобы вы были на 100% уверены, что никогда не ошибетесь в настройке приложения в рабочей среде, поскольку не поддерживают эту функцию. (Конечно, вы должны быть абсолютно уверены, что вы никогда не развернете двоичный файл, скомпилированный для тестирования в рабочей среде.) Я думаю, условная компиляция / условная компиляция - хороший выбор здесь.

Это все, что можно сказать об этом, нет?

1 голос
/ 11 января 2011

Я бы обернул вызовы проверкой статической переменной (unitTest). Таким образом, вы можете в любое время инициализировать поведение из файла конфигурации.

time_t myTime( time_t * timer ) 
{
    if ( unitTest ) {
        return TIME_TEST;
    }
    return time( timer );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...