2012-06-14 2 views
2

Справочная информация: У меня сложное приложение, которое унаследовало и распространяю (выпускной исследовательский проект). Я хочу убедиться, что мои реорганизации имеют положительный долгосрочный эффект на ремонтопригодность и удобство использования - другими словами, я хочу убедиться, что я поставил вопрос как можно более стандартным образом для будущих людей, которые могут работать над кодом. У меня нет времени, и это не мое место, до полностью переструктурируйте приложение.C++, общая библиотека, «модульные тесты» в основной функции

Приложение представляет собой экосистемную модель. Он состоит из общей библиотеки, написанной на C++, которая делает тяжелую работу. Библиотека включена в приложение Java, которое «управляет» симуляцией - обрабатывает некоторые операции ввода-вывода базы данных и предоставляет графический интерфейс.

В ходе моей разработки я добавил в проект ряд функций утилиты, в основном для удобной печати внутренних переменных на консоли (непосредственно из частей кода C++) во время выполнения.

Теперь я факторизую эти функции в файл утилиты (заголовок и cpp), который при необходимости входит в другие файлы. Я положил функции в своем собственном пространстве имен следующий пример здесь: Organising utility functions in C++

Вопрос: Если я хочу написать несколько тестов для функций полезности, так что я могу развиваться и экспериментировать без повторной компиляции и модификации/бега всю модель, где и как следует лучше всего включать эти тесты?

Будет ли проблема, если у меня есть функция main() в файле util.cpp? К моему удивлению, я пробовал это, и он работает; Я могу скомпилировать и запустить файл util.cpp независимо. Также основное приложение, которое включает util.cpp, все еще компилируется и работает нормально. Я был удивлен, потому что думал, что наличие второго main() будет проблемой - хотя точка входа приложения находится в java-коде.

Однако я не уверен, что это лучший маршрут; У меня недостаточно опыта, чтобы увидеть будущие подводные камни с этой тактикой.

Вот короткий пример файла мой util.cpp:

#include "util.hpp" 
#include <iostream> 
#include <vector> 
namespace util { 
    /** Prints a std::vector of doubles in a format that can be 
    * copied directly into a python console. */ 
    void util::pyprint_vec(const std::vector<double> & v){ 
    std::cout << "["; 
    for(std::vector<double>::const_iterator it = v.begin(); it != v.end(); ++it){ 
     std::cout << *it << ", "; 
    } 
    std::cout << "\b\b]"; // remove the last comma 
    } 
} 

int main() { 
    using namespace util; 
    using namespace std; 

    cout << "Testing some of the utility functions...\n"; 
    vector<double> a_vec(50,12.0); 
    pyprint_vec(a_vec); 
    cout << endl; 

    return 0; 
} 

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

ответ

1

Обычно вы хотите написать отдельную исполняемую программу, которая включает в себя модульные тесты и которая связывает функции, подлежащие тестированию. Например, вы можете создать util_test.cpp, который включает в себя функцию main() и код с тестами, и что * # include * s util.hpp. При компиляции используйте статические или динамические ссылки на код, который вы хотите протестировать.

Технически, не будет проблемы с функцией main() в util.cpp. Тем не менее, если вы включите вторую основную функцию в другое место в библиотеке (для модульного тестирования чего-то еще) и свяжите ее с одним и тем же общим объектом, вы получите ошибки компоновщика.

Основная функция не имеет особого значения, кроме того, когда компоновщик создает исполняемый файл, он вставляет специальный код, чтобы при запуске программы выполнялся код из основного. Если вы загружаете библиотеку «shared object», вы не «запускаете» программу, и до тех пор, пока вы не вызываете основную функцию явно, что код не будет выполнен.

+0

Прохладный, спасибо. Это определенно помощь. Я подозревал что-то подобное с разделяемой библиотекой. – tbc

0

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

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

+0

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

+0

Я не согласен с точкой «нескольких исполняемых файлов». Если вы работаете над проектом с> 50k строк unittests, вы будете вполне довольны, если вам не придется перекомпилировать все это, когда вы только сделали небольшое изменение в одном компоненте. – niko

+0

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

Смежные вопросы