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

#c #unit-testing #mocking #linker #cpputest

#c #модульное тестирование #насмешливый #компоновщик #cpputest

Вопрос:

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

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

Вот пример.

Используя CPPUTEST, я имею MockSupport_c.h в своем распоряжении. Итак, я пишу макет для его функции. Пример

реальная функция:

 int read_bytes(int count)
{
    // for loop read the bytes
    return success;
}
 

Я вызываю приведенное выше с моей функцией, которую я хочу протестировать

 int read()
{
    return read_bytes(256);
}
 

Тестовый модуль выглядит примерно следующим образом:

 
// create the mock
int read_bytes(int count)
{
    mock_c()->actualCall("read_bytes");
    return 1;
}

// test the code
TEST(group, test_name)
{
    mock_c()->expectOneCall("read_bytes");
    read();
    mock_c()->checkExpectations();
}
 

Когда модульный тест скомпилирован, компоновщик заменит реализацию производственного кода на макет версии; но он будет делать это для всех вызовов этой функции. Итак, модульные тесты моих коллег теперь вызывают mocks, когда он должен тестировать его фактические вызовы.

Как мне заставить макеты применяться только во время моих тестов, а не перезаписывать вызовы моих коллег?

Или я просто не совсем понимаю, как все это работает?

Комментарии:

1. Как вы компилируете и связываете? Почему вы не можете связать каждый тест с соответствующими реальными или фиктивными модулями?

2. После компиляции результатом является 1 отдельный исполняемый файл, который будет выполнять все тесты. При этом производственный код компилируется как библиотека, а макеты либо в своей собственной библиотеке, либо в основном исполнении; компоновщик (по замыслу) свяжет вызов с первой функцией, которая соответствует указанному вызову. Итак, если я сначала помещу макеты в командную строку, компоновщик выполнит все вызовы этого макета, затем загрузит рабочую библиотеку и заполнит остальное … и если я сначала помещу рабочую библиотеку в командную строку, тогда компоновщик свяжет все вызовы функций с реальным кодом, а не с исходным кодом.к макетам.

3. Я использую цепочку инструментов компилятора Visual Studio vc . В моем чтении я не обнаружил способа указать компоновщику, какие функции переключаются, а какие нет. Если есть способ сделать это, то я действительно хотел бы знать. Я уверен, что это решит проблему.

4. О, вау. Это требование вашего процесса разработки или CppUTest? Я действительно уверен, что платформа модульного тестирования предоставляет некоторые идеи, как справиться с этим. — Однако, если вам необходимо создать один исполняемый файл, вы можете использовать некоторую магию препроцессора, чтобы позволить компилятору различать варианты использования (реальный / макет).).

5. Нет никаких установленных требований к тому, как реализуется фреймворк модульного тестирования, есть только то, что мы это делаем. Так что у меня есть некоторая гибкость. Я решил выполнить замену во время соединения, потому что я считаю, что это самое чистое решение для переключения функций без изменения базы производственного кода. Засорение нашего кода #ifdef — это не то, что нравится команде. Наличие нескольких исполняемых файлов является приемлемым решением, если управление ими является простым и автоматизированным решением. Это то, что я не изучал досконально, поэтому дополнительная информация приветствуется.