是否可以以任何方式将BOOST_AUTO_TEST_CASE
和BOOST_AUTO_TEST_CASE_TEMPLATE
宏与BOOST_PARAM_TEST_CASE
混淆?我甚至对实现这一目标的方法非常感兴趣。
手动构建所有测试用例似乎非常繁琐。但是BOOST_PARAM_TEST_CASE
机制非常有用,但只有在你有一个测试初始化函数时才有效,这反过来要求你使用手动测试用例构建。
是否有关于如何自行挂钩自动系统的文档,以便您可以提供自己的自动注册测试?
我现在正在使用boost 1.46。
答案 0 :(得分:12)
我为此写了自己的支持,因为似乎没有任何好的支持。这需要C ++ 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 ¶m) \
{ \
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 ¶m) \
// *******
#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 ¶m) \
{ \
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 ¶m) \
// *******
#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 ¶m) \
{ \
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 ¶m) \
#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 ¶m) : F(param) {} \
void test_method(void); \
}; \
\
void BOOST_AUTO_TC_INVOKER( test_name )(const test_name::param_t ¶m)\
{ \
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)