2014-01-24 11 views
1

Я расширяю библиотеку для вычислительной динамики жидкости, поэтому я имею дело с устаревшим кодом. Приложения включают в себя инициализацию иногда очень больших объектов, большинство из которых являются взаимозависимыми. Инициализация зависит от файлов конфигурации и ввода, хранящихся в каталоге.Возможно ли объявить тесты Boost.UnitTest в основном так, как Boost.MinimalTestFacility?

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

Однако у меня возникла проблема при попытке называть конкретные тесты в определенных точках в программе. Эта проблема произошла уже тогда, когда я попытался использовать тест Google - см this question.

Вот модель задачи с помощью Boost.Test:

#define BOOST_TEST_MODULE hugeObjectEvenTest 
#define BOOST_TEST_NO_MAIN 
#include <boost/test/included/unit_test.hpp> 
#include<random> 
#include<iostream> 

BOOST_AUTO_TEST_SUITE (hugeObjectEvenTest) 

BOOST_AUTO_TEST_CASE (test1) 
{ 
    BOOST_CHECK(hugeObject.value() % 2 == 0); 
} 

BOOST_AUTO_TEST_SUITE_END() 

class HugeClass 
{ 
    int value_ = 0; 

    public: 

     HugeClass() = default; 

     HugeClass(int x) : value_(x) {}; 

     int value() { return value_; } 

     void setValue (int val) { value_ = val; } 
}; 

int main(int argc, const char *argv[]) 
{ 
    HugeClass hugeObject; 

    std::random_device rd; 
    std::default_random_engine e1(rd()); 
    std::uniform_int_distribution<int> dist(0,100); 

    for(int i = 0; i < 10; ++i) 
    { 
     hugeObject.setValue(dist(e1)); 
     std::cout << hugeObject.value() << std::endl; 
    } 

    return 0; 
} 

Это просто модель численного приложения решателя, как и найдено here.

Что я думаю Мне нужен глобальный светильник, который может принять ссылку на hugeObject.

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

Все, что я хочу сделать, - это выполнить конкретные тесты в определенных точках внутри основного и извлечь выгоду из наличия тестового дерева и всех других преимуществ использования рамки тестирования. Что-то похожее на функциональность Minimal Test Facility.

Возможно ли это с помощью Boost.Test? Как и Google Test, выбор конкретных тестов может быть сделан parsing during execution. Это бесполезно для моей проблемы. Я использовал GTest и BoostTest для модульных тестов, где инициализация светильников является локальной и не зависит от основных (argc, argv, конфигурационных и входных файлов), и у меня не было проблем.

Редактирование: Я, вероятно, поплачу за это, но, имея дело с устаревшим кодом, я считаю, что было бы полезно как-то получить доступ к объектам в основном через const refs (чтобы убедиться, что тесты не изменяются объектов), проще, чем наследование классов классов. В моем случае это означает день работы, по сравнению с простым BOOST_TEST_REQUIRE, размещенным в основном при использовании минимальной основы тестирования. Конечно, с минимальной каркасом у меня нет тестового дерева и т. Д., Поэтому я вернулся туда, где начал: в моей собственной взломанной тестовой библиотеке.

ответ

1

Один из возможных способов сделать это - выполнить собственную регистрацию вручную, отделить тесты, которые вы хотите выполнить вместе, в комплекты и запустить их вручную. Например:

using namespace boost::unit_test; 

void test1() { std::cout << "Running test 1\n"; } 
void test2() { std::cout << "Running test 2\n"; } 
void test3() { std::cout << "Running test 3\n"; } 

void init_test_tree() { 

    test_suite *ts1 = BOOST_TEST_SUITE("suite_a"); 
    ts1->add(BOOST_TEST_CASE(&test1)); 
    ts1->add(BOOST_TEST_CASE(&test2)); 
    framework::master_test_suite().add(ts1); 

    test_suite *ts2 = BOOST_TEST_SUITE("suite_b"); 
    ts2->add(BOOST_TEST_CASE(&test3)); 
    framework::master_test_suite().add(ts2); 
} 

bool empty_init() { return true; } 

int main(int argc, char *argv[]) { 

    init_test_tree(); 

    std::cout << "Run suite a\n"; 
    framework::run(framework::master_test_suite().get("suite_a")); 

    std::cout << "Run suite b\n"; 
    framework::run(framework::master_test_suite().get("suite_b")); 

    std::cout << "Run the tree\n"; 
    // pass empty initialization function as we've already constructed the test tree 
    return unit_test_main(&empty_init, argc, argv); 
} 
+0

Спасибо за идею, но я до сих пор не вижу, как функции {1..3} проверяют объекты, инициализированные в main. – tmaric

+1

В этом примере это не так, однако при инициализации тестовых наборов с помощью светильников нетрудно инициализировать сборку тестового дерева. Используйте макрос 'BOOST_FIXTURE_TEST_SUITE' вместо' BOOST_TEST_SUITE'. См. Также примеры в дистрибутиве источника ускорения. –

+0

Хорошо, спасибо большое, я дам ему прямо сейчас. Сначала я спрашиваю, потому что я буду упаковывать инициализацию объекта в течение как минимум нескольких часов. :) – tmaric

0

Регистрация собственных тестовых примеров вручную утомительна, скучна и подвержена ошибкам, и я не рекомендую ее. Вместо этого вы можете просто определить свой собственный main() вместо того, чтобы Boost.Test предоставить его вам.Написать main который выглядит следующим образом:

HugeClass hugeObject; 

boost::unit_test::test_suite *init_function(int argc, char *argv[]) 
{ 
    // create test cases and suites and return a pointer to any enclosing 
    // suite, or 0. 
    return 0; 
} 

int main(int argc, const char *argv[]) 
{ 
    std::random_device rd; 
    std::default_random_engine e1(rd()); 
    std::uniform_int_distribution<int> dist(0,100); 

    for(int i = 0; i < 10; ++i) 
    { 
     hugeObject.setValue(dist(e1)); 
     std::cout << hugeObject.value() << std::endl; 
    } 
    return boost::unit_test::unit_test_main(init_function, argc, argv); 
} 

Если вы сделаете это, вы получите:

  • регистрация Автоматический тест
  • Использование тестовых наборов
  • Возможность делать никаких специальных вещей сначала в main() перед любой частью Boost.Test работает

Один annoyin g побочный эффект написания вашего основного: подпись для init_function различна в зависимости от того, связана ли вы со статической версией Boost.Test или с общей библиотечной (динамической) версией Boost.Test. Различия обсуждаются в моих Boost.Test documentation rewrite в разделах на static library и shared library.