是否可以在boost :: test上使用BOOST_PARAM_TEST_CASE并自动注册?

时间:2011-11-10 17:54:22

标签: c++ unit-testing boost

是否可以以任何方式将BOOST_AUTO_TEST_CASEBOOST_AUTO_TEST_CASE_TEMPLATE宏与BOOST_PARAM_TEST_CASE混淆?我甚至对实现这一目标的方法非常感兴趣。

手动构建所有测试用例似乎非常繁琐。但是BOOST_PARAM_TEST_CASE机制非常有用,但只有在你有一个测试初始化​​函数时才有效,这反过来要求你使用手动测试用例构建。

是否有关于如何自行挂钩自动系统的文档,以便您可以提供自己的自动注册测试?

我现在正在使用boost 1.46。

6 个答案:

答案 0 :(得分:12)

我为此写了自己的支持,因为似乎没有任何好的支持。这需要C ++ 11 decltype功能以及::std::remove_const::std::remove_reference库方法。

宏定义是BOOST_FIXTURE_TEST_CASEBOOST_AUTO_TEST_CASE宏的修改版本。

您可以通过声明您的功能来使用它:

BOOST_AUTO_PARAM_TEST_CASE(name, begin, end)
{
    BOOST_CHECK_LT(param, 5);  // The function will have an argument named 'param'.
}

以下是定义BOOST_AUTO_PARAM_TEST_CASE宏的标题:

#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#include <type_traits>

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend )     \
struct test_name : public F {                                           \
   typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
   void test_method(const param_t &);                                   \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       (mbegin), (mend)));                                              \
                                                                        \
void test_name::test_method(const param_t &param)                       \

// *******

#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  mbegin, mend)

答案 1 :(得分:5)

@Omnifarious提供的解决方案有效,但需要C ++ 11编译器。

为C ++ 03编译器调整该解决方案:

#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, P, mbegin, mend )  \
struct test_name : public F                                             \
{                                                                       \
    typedef P param_t;                                                  \
    void test_method(const param_t &);                                  \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       (mbegin), (mend)));                                              \
                                                                        \
void test_name::test_method(const param_t &param)                       \

// *******

#define BOOST_AUTO_PARAM_TEST_CASE( test_name, param_type, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  param_type,                           \
                                  mbegin, mend)

此解决方案的用法略有不同。由于C ++ 03中没有declspec,因此无法自动推导出参数对象的类型。我们必须将其作为参数传递给BOOST_AUTO_PARAM_TEST_CASE

class FooTestParam                           
{    
public:                        
    std::string mS;    

    FooTestParam (int n)    
    {            
        std::stringstream ss;    
        ss << n;         
        mS = ss.str();                            
    }    
};         

FooTestParam fooParams [] =    
{         
    FooTestParam (42),    
    FooTestParam (314)    
};           

BOOST_AUTO_PARAM_TEST_CASE (TestFoo, FooTestParam, fooParams, fooParams + 2)        
{                                                                                   
    const std::string testVal = param.mS;                                           
}                                                                                   

BOOST_AUTO_TEST_CASE (TestAddressField)                                             
{                                                                                   
    const uint32_t raw = 0x0100007f;    // 127.0.0.1                                
    const uint8_t expected[4] = {127, 0, 0, 1};                                     
    const Mdi::AddressField& field = *reinterpret_cast <const Mdi::AddressField*> (&raw);    
    for (size_t i = 0; i < 4; ++i)                                                  
        BOOST_CHECK_EQUAL (field[i], expected[i]);                                  
}                                                                                   

答案 2 :(得分:3)

您可以轻松混合手动和自动测试单元注册。实现自己的init函数(如this页面上的示例20)和init函数内部,您可以执行参数化测试用例的注册。 Boost.Test会将它们合并到单个测试树中。

答案 3 :(得分:2)

自Boost 1.59实现的内部细节发生了变化,Omnifarious的解决方案无法编译。

正在改变boost::unit_test::make_test_case功能的签名的原因:现在需要2个额外的参数:__FILE__, __LINE__

固定解决方案:

#if BOOST_VERSION > 105800
#define MY_BOOST_TEST_ADD_ARGS __FILE__, __LINE__,
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR ,boost::unit_test::decorator::collector::instance()
#else
#define MY_BOOST_TEST_ADD_ARGS
#define MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR
#endif

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend )     \
struct test_name : public F {                                           \
   typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
   void test_method(const param_t &);                                   \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param) \
{                                                                       \
    test_name t;                                                        \
    t.test_method(param);                                               \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       MY_BOOST_TEST_ADD_ARGS                                           \
       (mbegin), (mend))                                                \
       MY_BOOST_TEST_DEFAULT_DEC_COLLECTOR);                            \
                                                                        \
void test_name::test_method(const param_t &param)                       \




#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  mbegin, mend)

答案 4 :(得分:2)

从Boost版本1.59开始,这由data-driven test cases处理:

#define BOOST_TEST_MODULE MainTest

#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/array.hpp>

static const boost::array< int, 4 > DATA = { 1, 3, 4, 5 };

BOOST_DATA_TEST_CASE( Foo, DATA )
{
    BOOST_TEST( sample % 2 );
}

此功能需要编译器和库的C ++ 11支持。

答案 5 :(得分:0)

我使用了Omnifarious'头文件并对其进行了修改,使得参数传递给测试夹具的构造函数而不是测试方法。这要求测试夹具的构造函数声明采用参数类型的单个参数。我发现这非常方便 - 非常感谢最初的问题和答案!

#include <boost/test/unit_test_suite.hpp>
#include <boost/test/parameterized_test.hpp>
#include <type_traits>

#define BOOST_FIXTURE_PARAM_TEST_CASE( test_name, F, mbegin, mend )     \
struct test_name : public F {                                           \
    typedef ::std::remove_const< ::std::remove_reference< decltype(*(mbegin)) >::type>::type param_t; \
    test_name(const param_t &param) : F(param) {}                       \
    void test_method(void);                                             \
};                                                                      \
                                                                        \
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t &param)\
{                                                                       \
    test_name t(param);                                                 \
    t.test_method();                                                    \
}                                                                       \
                                                                        \
BOOST_AUTO_TU_REGISTRAR( test_name )(                                   \
    boost::unit_test::make_test_case(                                   \
       &BOOST_AUTO_TC_INVOKER( test_name ), #test_name,                 \
       (mbegin), (mend)));                                              \
                                                                        \
void test_name::test_method(void)                                       \

// *******

#define BOOST_AUTO_PARAM_TEST_CASE( test_name, mbegin, mend )           \
   BOOST_FIXTURE_PARAM_TEST_CASE( test_name,                            \
                                  BOOST_AUTO_TEST_CASE_FIXTURE,         \
                                  mbegin, mend)