Можно ли использовать BOOST_PARAM_TEST_CASE с автоматической регистрацией на boost:: test?

Можно ли каким-либо образом смешать макросы BOOST_AUTO_TEST_CASE и BOOST_AUTO_TEST_CASE_TEMPLATE с помощью BOOST_PARAM_TEST_CASE? Меня даже интересуют действительно грязные способы сделать это.

Приобретение всех ваших тестовых примеров вручную кажется действительно утомительным. Но механизм BOOST_PARAM_TEST_CASE довольно полезен, но работает только в том случае, если у вас есть функция тестирования init, которая, в свою очередь, требует, чтобы вы использовали ручную конструкцию тестового сценария.

Есть ли какая-либо документация о том, как подключиться к автоматической системе самостоятельно, чтобы вы могли предоставить свои собственные тесты, которые автоматически регистрируются?

Я использую boost 1.46 прямо сейчас.

Ответ 1

Начиная с версии Boost 1.59, это обрабатывается управляемыми данными тестовыми сценариями:

#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 );
}

Эта функция требует поддержки С++ 11 из компилятора и библиотеки.

Ответ 2

Я написал свою собственную поддержку для этого, поскольку действительно не было никакой хорошей поддержки. Для этого требуется функция С++ 11 decltype и методы библиотеки ::std::remove_const и ::std::remove_reference.

Определения макросов представляют собой измененные версии макросов BOOST_FIXTURE_TEST_CASE и BOOST_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)

Ответ 3

Решение, предоставляемое работами @Omnifarious, работает, но требует компилятор С++ 11.

Адаптация этого решения для компилятора С++ 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)

Это решение немного отличается от использования. Поскольку в С++ 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]);                                  
}                                                                                   

Ответ 4

Вы можете легко перемещать ручную и автоматическую регистрацию тестового модуля. Внесите свою собственную функцию init (например, в примере 20 на странице this) и внутри функции init вы можете выполнить регистрацию для параметризованных тестовых случаев. Boost.Test объединит их как в одно тестовое дерево.

Ответ 5

Поскольку Boost 1.59 внутренние детали реализации были изменены, а решение Omnifarious не компилируется.

Причина o меняет подпись функции 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)

Ответ 6

Я взял файл заголовка Omnifarious и изменил его таким образом, чтобы этот параметр передавался конструктору тестового прибора, а не методу тестирования. Для этого требуется, чтобы объявление конструктора testmax принимало один аргумент с типом параметра. Я нашел, что это супер удобно - спасибо за начальный вопрос и ответ!

#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)