C++ 单元测试一个对象,该对象采用;“特征”;模板参数

C++ 单元测试一个对象,该对象采用;“特征”;模板参数,c++,unit-testing,googletest,googlemock,C++,Unit Testing,Googletest,Googlemock,我有一个VisualStudio2008C++03项目,我想对一个类进行单元测试,该类使用一个traits模板参数来公开静态方法(基于策略的设计、策略模式)。我正在使用谷歌测试和谷歌模拟框架 例如: /// the class under test template< typename FooTraits > class Foo { public: void DoSomething() { FooTraits::handle_type h = FooT

我有一个VisualStudio2008C++03项目,我想对一个类进行单元测试,该类使用一个traits模板参数来公开静态方法(基于策略的设计、策略模式)。我正在使用谷歌测试和谷歌模拟框架

例如:

/// the class under test
template< typename FooTraits >
class Foo
{
public:
    void DoSomething()
    {
        FooTraits::handle_type h = FooTraits::Open( "Foo" );
        /* ... */
        FooTraits::Close( h );
    };
};

/// a typical traits structure
struct SomeTraits
{
    typedef HANDLE handle_type;
    static handle_type Open( const char* name ) { /* ... */ };
    static void Close( handle_type h ) { /* ... */ };
};

/// mocked traits that I would like to use for testing
struct MockTraits
{
    typedef int handle_type;
    static MOCK_METHOD1( Open, handle_type( const char* ) );
    static MOCK_METHOD1( Close, void( handle_type ) );
};

/// the test function
TEST( FooTest, VerifyDoSomethingWorks )
{
    Foo< MockTraits > foo_under_test;

    // expect MockTraits::Open is called once
    // expect MockTraits::Close is called once with the parameter returned from Open
    foo_under_test.DoSomething();
};
///正在测试的类
模板
福班
{
公众:
无效剂量测定法()
{
脚踏板::手柄类型h=脚踏板::打开(“Foo”);
/* ... */
足迹::闭合(h);
};
};
///典型特征结构
结构特征
{
typedef HANDLE\u类型;
静态句柄类型Open(const char*name){/*…*/};
静态无效闭合(句柄类型h){/*…*/};
};
///我想用于测试的模拟特征
结构模拟特征
{
typedef int handle_type;
静态模拟方法1(打开,句柄类型(常量字符*);
静态模拟方法1(关闭、无效(句柄类型));
};
///测试功能
测试(最足部,验证dosomethingWorks)
{
FooFoo_测试;
//expect MockTraits::Open只调用一次
//expect MockTraits::Close调用一次,参数从Open返回
foo_在_测试下。DoSomething();
};
显然,这不会像现在这样起作用。GoogleMock不能模拟静态方法,我需要在测试中创建模拟类的实例来设置其行为和期望


那么,使用Google test/Google Mock对接受模板策略的类进行单元测试的正确方法是什么呢?

您可以使用非静态方法创建一个类,创建它的全局实例(或在traits中创建静态实例),并让traits类服从它吗

因此,为了澄清Rob的评论所激发的想法:

struct FunnyDoodad
{
   FunnyDoodad();
   ~FunnyDoodad();

   MOCK_METHOD1( Open, HANDLE( const char* ) );
   MOCK_METHOD1( Close, void( handle_type ) );

};

struct FunnyGlobal {
  FunnyGlobal() : pimpl() {}
  ~FunnyGlobal() { delete pimpl; }

  // You'd want some protection here rather than just dereferencing.
  // it's the whole point.  I'd suggest using whatever unit test assertion
  // mechanism your framework uses and make it a fatal check.    
  handle_type Open(char const* name) { return pimpl->Open(name); }
  void Close(handle_type h) { pimpl->Close(h); }
private:
   FunnyDoodad * pimpl;

  friend struct FunnyDoodad;

  void register(FunnyDoodad* p) { pimpl = p; }
  void deregister() { pimpl = 0; }
};

FunnyGlobal funnyGlobal;

FunnyDoodad::FunnyDoodad() { funnyGlobal.register(this); }
FunnyDoodad::~FunnyDoodad() { funnyGlobal.deregister(); }

struct TestTraits
{
    typedef HANDLE handle_type;
    static handle_type Open( const char* name ) { return funnyGlobal.Open(name); };
    static void Close( handle_type h ) { funnyGlobal.Close(h); };
};

TEST_CASE(blah)
{
   FunnyDoodad testDoodad;

   ...
}

我想上面的内容可以被模板化,几乎变成一种模式……也许吧。

这真是一种天才。创建一个被模拟的单例类,然后使用该类的存根引用。你能把它写进一个答案吗?我想单击绿色的小复选标记。您可能不会真的希望使模拟实例成为静态或全局的。一个测试的操作可能会干扰后续测试的处理。相反,使用指向trait实例的全局或静态指针。在每个测试中声明一个本地模拟特征类,并将全局指向它。@RobKennedy-我不知道这一点。我可以看到你要去哪里,但是取消对指针的引用会导致错误。你考试中的一个失误可能会导致什么,谁知道呢……包括及格(如果你特别不走运的话,我可以看到它会发生的方式)。因此,我建议做一些比指针更聪明的事情。一个静态对象的工作是引用一个测试本地对象,该对象将使用类似RAII的概念来注册/注销这个对象。这可能是绝对安全的方法,每次测试都会重置。