是否可以在main中以类似于Boost.MinimalTestFacility的方式调用Boost.UnitTest测试



我正在扩展一个用于计算流体动力学的库,所以我正在处理遗留代码。应用程序有时涉及初始化非常大的对象,其中大多数是相互依赖的。初始化取决于存储在目录中的配置和输入文件。

与我自己的测试黑客库相比,尝试使用测试框架应该是有意义的,因为有各种测试用例和家族以及测试,我可以从拥有测试树和闪亮的报告 + 自动化测试的能力中受益。

但是,在尝试在程序的特定点调用特定测试时,我遇到了一个问题。当我尝试使用谷歌测试时,这个问题已经发生了 - 请参阅这个问题。

下面是使用 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;
}

这只是一个数值求解器应用程序的模型,就像这里找到的那样。

我认为我需要的是一个能够参考hugeObject的全球固定装置。

hugeObject一样的实例在模拟循环(使用 for 循环建模)内进行修改(使用随机数生成建模)。

我想做的只是在main中的特定点执行特定的测试,并从拥有测试树以及使用测试框架的所有其他好处中受益。类似于最小测试设施的功能。

这在Boost.Test中可能吗?与谷歌测试一样,选择特定的测试可以通过在执行期间进行解析来完成。这对我的问题没有任何用处。我已经使用GTest和BoostTest进行单元测试,其中夹具的初始化是本地的,不依赖于main(argc,argv,配置和输入文件),我没有问题。

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

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

using namespace boost::unit_test;
void test1() { std::cout << "Running test 1n"; }
void test2() { std::cout << "Running test 2n"; }
void test3() { std::cout << "Running test 3n"; }
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 an";
framework::run( framework::master_test_suite().get("suite_a"));
std::cout << "Run suite bn";
framework::run( framework::master_test_suite().get("suite_b"));
std::cout << "Run the treen";
// 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);
}

如果这样做,您将获得:

  • 自动测试用例注册
  • 使用测试套件
  • 在 Boost 的任何部分运行之前先在main()中执行任何特殊操作的能力.Test 运行

编写自己的 main 的一个烦人的副作用是:init_function的签名是不同的,具体取决于您是与静态版本的 Boost.Test 还是共享库(动态)版本的 Boost.Test 链接。 这些差异在我的 Boost.Test 文档重写中讨论了静态库和共享库的部分。

最新更新