【问题标题】:Is it possible to envoke Boost.UnitTest tests within main in a way similar to the Boost.MinimalTestFacility?是否可以以类似于 Boost.MinimalTestFacility 的方式在 main 中调用 Boost.Unit Test 测试?
【发布时间】:2014-01-24 11:05:41
【问题描述】:

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

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

但是,当我尝试在程序中在特定点调用特定测试时遇到了问题。当我尝试使用 Google Test 时,已经出现了这个问题 - 请参阅 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循环建模)被修改(用随机数生成建模)。

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

Boost.Test 是否可以做到这一点?和谷歌测试一样,选择具体的测试可以通过parsing during execution来完成。这对我的问题没有任何用处。我已经将 GTest 和 BoostTest 都用于单元测试,其中固定装置的初始化是本地的,不依赖于 main(argc、argv、配置和输入文件),我没有任何问题。

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

【问题讨论】:

    标签: c++ boost-test


    【解决方案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);
    }
    

    【讨论】:

    • 感谢您的想法,但我仍然看不到 test{1..3} 函数如何访问在 main 中初始化的对象。
    • 在这个例子中它们不是,但是当你构建测试树时用fixture初始化测试套件并不难。使用BOOST_FIXTURE_TEST_SUITE 宏而不是BOOST_TEST_SUITE。另请参阅 boost 测试源分发中的示例。
    • 好的,非常感谢,我现在就试试。我先问一下,因为我将在至少几个小时内打包对象初始化。 :)
    【解决方案2】:

    手动注册您自己的测试用例是乏味、乏味且容易出错的,我不建议这样做。相反,您可以简单地定义自己的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.Test 的任何部分运行之前首先在 main() 中执行任何特殊操作的能力

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-12
      • 2010-12-03
      • 2019-04-04
      • 1970-01-01
      • 1970-01-01
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多