是否有可能以类似于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);
}
手动注册您自己的测试用例是单调乏味,乏味和容易出错的,我不推荐它。相反,您可以简单地定义自己的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 rewrite的static library和shared library部分进行了讨论。
感谢您的想法,但我仍然看不到测试{1..3}函数如何访问在main中初始化的对象。 – tmaric
在这个例子中,他们不是,但是当你构建测试树时,用夹具初始化测试套件并不困难。使用'BOOST_FIXTURE_TEST_SUITE'宏而不是'BOOST_TEST_SUITE'。另请参阅升压测试源分布中的示例。 –
好,非常感谢,我现在就去试试吧。我首先问,因为我将包装对象初始化至少几个小时。 :) – tmaric