CPPUNIT:我们真的每次测试都需要一个函数吗?

Posted

技术标签:

【中文标题】CPPUNIT:我们真的每次测试都需要一个函数吗?【英文标题】:CPPUNIT: do we really need one function per test? 【发布时间】:2016-11-30 15:53:40 【问题描述】:

考虑这个 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&lt;1,2&gt;) );),报错:

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); 有帮助吗? 我需要将三个测试分开运行(根据您的建议,如果第一个失败,则不执行最后两个) 看here。你不能在那里使用std::string,但char* 会起作用。这是一个语言规范。您能否发布使用 lambda 的完整堆栈(我忘记在我的答案中保护它,现在已修复)。 @kabanus:在您的帖子中添加了完整的错误消息作为编辑。 【参考方案1】:

通过创建多个测试类(而不是一个包含多个子测试的单一类)找到了解决方案。

只有一个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“下一个版本”?上一个版本 (1.12.2) 是在 2008 年制作的,所以我怀疑下一个版本即将推出...... freedesktop.org/wiki/Software/cppunit 或多或少是所有 linux 发行版的新家和版本。那个由 LibreOffice 团队维护。 @moggi:很高兴知道,有一天我会尝试升级到那个版本!谢谢

以上是关于CPPUNIT:我们真的每次测试都需要一个函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

单元测试的测试工具

CppUnit 中的类似 TestFixtureSetUp 的方法

你真的了解方法吗?

它们真的是Python内置函数吗?

Pex(测试生成)真的有用吗?

骆驼真的会被最后一根稻草压死吗?