是否有可能以类似于Boost.MinimalTestFacility的方式在主要内部启动Boost.UnitTest测试?

问题描述:

我正在扩展一个用于计算流体动力学的库,所以我正在处理遗留代码。这些应用程序涉及初始化有时非常大的对象,其中大部分对象是相关的。初始化取决于存储在目录中的配置和输入文件。是否有可能以类似于Boost.MinimalTestFacility的方式在主要内部启动Boost.UnitTest测试?

试图使用测试框架相比,我自己的测试被黑客入侵的库应该是有道理的,因为有各种测试用例和家庭,测试,我可以受益于测试树和闪亮的报告+自动化的能力试验。

但是,我试图在程序中的特定点处尝试调用特定测试时遇到了问题。当我尝试使用谷歌测试该问题已经发生 - 见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

在模拟过程中(使用for循环建模)仿真期间修改(如随机数生成模型)hugeObject的实例。

我想要做的就是在main中的特定点执行特定的测试,并从测试树中受益,以及使用测试框架的所有其他特性。类似于Minimal Test Facility的功能。

这是所有可能与Boost.Test?像谷歌测试一样,选择特定的测试可以通过parsing during execution完成。这对我的问题毫无用处。我已经使用GTest和BoostTest进行单元测试,其中灯具的初始化是本地的,并且不依赖于main(argc,argv,配置和输入文件),并且我没有问题。

编辑:我很可能会因此而发火,但是在处理遗留代码时,我相信以某种方式能够通过const refs访问main中的对象将是有益的(以确保测试不会修改对象),而不是从夹具类继承。就我而言,这意味着需要一天的工作,而使用最小化测试框架时,与简单的BOOST_TEST_REQUIRE放在主内部相比。当然,用最小的框架我没有测试树等,所以我回到了我开始的地方:在我自己的黑客测试库。

执行此操作的一种可能方法是执行自己的手动测试注册,将要执行的测试分离到套件中并手动运行它们。例如:

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

手动注册您自己的测试用例是单调乏味,乏味和容易出错的,我不推荐它。相反,您可以简单地定义自己的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的任何部分运行

一个恼人的g编写自己的main的副作用:init_function的签名会有所不同,具体取决于您是否与Boost.Test的静态版本或Boost.Test的共享库(动态)版本链接。这些差异在Boost.Test documentation rewritestatic libraryshared library部分进行了讨论。