CPPUNIT:我们真的需要为每个测试编写一个函数吗?

4
考虑下面这个CPPUNIT测试类,旨在使用不同的参数执行相同的测试(doTest):
class MyTest : public CPPUNIT_NS::TestFixture
{
  CPPUNIT_TEST_SUITE( MyTest );
  CPPUNIT_TEST( test1 );
  CPPUNIT_TEST( test2 );
  CPPUNIT_TEST( test3 );
  CPPUNIT_TEST_SUITE_END();

public:
  MyTest();

  void test1() { doTest(1); }
  void test2() { doTest(2); }
  void test3() { doTest(3); }

  void doTest( int param );
};
CPPUNIT_TEST_SUITE_REGISTRATION(MyTest);

有没有办法改变这种情况,避免不得不声明test1test2test3,例如:

class MyTest : public CPPUNIT_NS::TestFixture
{
  CPPUNIT_TEST_SUITE( MyTest );
  CPPUNIT_TEST_PARAM( doTest, 1 ); // CPPUNIT_TEST_PARAM does not exits, it's just to illustrate my need
  CPPUNIT_TEST_PARAM( doTest, 2 ); // CPPUNIT_TEST_PARAM does not exits, it's just to illustrate my need
  CPPUNIT_TEST_PARAM( doTest, 3 ); // CPPUNIT_TEST_PARAM does not exits, it's just to illustrate my need
  CPPUNIT_TEST_SUITE_END();

public:
  MyTest();

  void doTest( int param );
};
CPPUNIT_TEST_SUITE_REGISTRATION(MyTest);

请注意,CPPUNIT_TEST是一个宏:
#define CPPUNIT_TEST( testMethod )                        \
    CPPUNIT_TEST_SUITE_ADD_TEST(                           \
        ( new CPPUNIT_NS::TestCaller<TestFixtureType>(    \
                  context.getTestNameFor( #testMethod),   \
                  &TestFixtureType::testMethod,           \
                  context.makeFixture() ) ) )

编辑:

尝试了这个:

CPPUNIT_TEST_SUITE( MyTest );
CPPUNIT_TEST( funcT<1> );
CPPUNIT_TEST_SUITE_END();

template<int i> void funcT() { doTest(i); }

这段代码在使用时没有问题,但如果我使用 char* 类型就会失败:

CPPUNIT_TEST_SUITE( MyTest );
CPPUNIT_TEST( funcT<"foo"> );
CPPUNIT_TEST_SUITE_END();

template<char* s> void funcT() { std::cout << s << std::endl; doTest(1); }

它出现了错误:

error C2664: 'CppUnit::TestCaller<test_cppunit_regulation_regul_dt_100::TestFixtureType>::TestCaller(const CppUnit::TestCaller<test_cppunit_regulation_regul_dt_100::TestFixtureType> &)': cannot convert argument 2 from 'void (__cdecl *)(void)' to 'void (__cdecl test_cppunit_regulation_regul_dt_100::* )(void)'

或者更多参数:

CPPUNIT_TEST_SUITE( MyTest );
CPPUNIT_TEST( funcT<1,2> );
CPPUNIT_TEST_SUITE_END();

template<int i, int j> void funcT() { doTest(i+j); }

它出现了错误:

1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): warning C4002: too many actual parameters for macro 'CPPUNIT_TEST'
1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2059: syntax error: ')'

最后尝试添加括号 (CPPUNIT_TEST( (funcT<1,2>) ); ),出现错误:

1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2589: '(': illegal token on right side of '::'
1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2059: syntax error: '::'
1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2660: 'CppUnit::TestSuiteBuilderContextBase::addTest': function does not take 2 arguments
1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2143: syntax error: missing ';' before ')'
1>b:\dev\vobs_diabeloop\private\tst\regulation\cppunit\regul_dt_100\test.cpp(14): error C2059: syntax error: ')'

我不知道CppUnit的惯用法,但是void test1() { doTest(1); doTest(2); doTest(3); }会有所帮助吗? - Mark B
我需要将这三个测试分开来运行,以便它们都能被执行(如果第一个测试失败,则后面两个测试不会被执行)。 - jpo38
请点击这里。你不能在那里使用std::string,但是可以使用char*。这是一项语言规范。您能否发布使用lambda的完整堆栈(我忘记在我的答案中保护它了,现在已经修复)。 - kabanus
@kabanus:作为编辑,我已经在您的帖子中添加了完整的错误信息。 - jpo38
1个回答

0
找到了一个解决方案,通过创建多个测试类(而不是一个包含多个子测试的单一测试类)。
只有一个int参数的简单情况:
class BaseTest : public CPPUNIT_NS::TestFixture
{
public:
    BaseTest() {}

    void doTest( int param ) {}
};

template < int i >
class MyTest : public BaseTest
{
    CPPUNIT_TEST_SUITE(MyTest<i>);
    CPPUNIT_TEST( doTest );
    CPPUNIT_TEST_SUITE_END();

    void doTest()
    {
        BaseTest::doTest( i );
    };
};

#define REGISTER_TEST_WITH_PARAMS( name, a ) \
        CPPUNIT_TEST_SUITE_REGISTRATION( MyTest<a> );

REGISTER_TEST_WITH_PARAMS( test1, 1 );
REGISTER_TEST_WITH_PARAMS( test2, 2 );

如果需要更多的参数,只需创建一个类来封装它们:
class BaseTest : public CPPUNIT_NS::TestFixture
{
public:
    BaseTest() {}

    void doTest( int param1, const std::string& param2 ) {}
};

class ParamClass
{
public:
    ParamClass( int param1, const std::string& param2 ) :
        param1( param1 ),
        param2( param2 )
    {

    }

    int param1;
    std::string param2;
};

template < ParamClass & T >
class CURRENT_MODULE : public BaseTest
{
    CPPUNIT_TEST_SUITE(MyTest<T>);
    CPPUNIT_TEST( doTest );
    CPPUNIT_TEST_SUITE_END();

    void doTest()
    {
        BaseTest::doTest( T.param1, T.param2 );
    };
};

#define REGISTER_TEST_WITH_PARAMS( name, a, b ) \
        ParamClass name( a, b ); \
        CPPUNIT_TEST_SUITE_REGISTRATION( MyTest<name> );

REGISTER_TEST_WITH_PARAMS( test1, 1, "test1" );
REGISTER_TEST_WITH_PARAMS( test2, 2, "test2" );

cppunit的下一个版本将包含参数化测试用例。不幸的是,目前还不清楚它何时会发布。希望在月底之前,但可能会有一些延迟。 - moggi
@moggi "下一个版本"?最后一个版本(1.12.2)是在2008年发布的,所以我怀疑很快就不会有下一个版本了... - jpo38
https://www.freedesktop.org/wiki/Software/cppunit/ 大致上是新的主页,也是所有Linux发行版所提供的版本。这个版本由LibreOffice团队维护。 - moggi
@moggi:好的,我会尝试升级到那个版本的!谢谢。 - jpo38

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接