3

Visual Studio 2008 C++03 プロジェクトで、静的メソッド (ポリシー ベースの設計、戦略パターン) を公開する特性テンプレート パラメーターを使用するクラスを単体テストしたいと考えています。Google Test と Google Mock フレームワークを使用しています。

例えば:

/// 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();
};

明らかに、このままでは機能しません。Google Mock は静的メソッドをモックできないため、テストで Mocked クラスのインスタンスを作成して、その動作と期待値を設定する必要があります。

では、Google Test / Google Mock を使用してテンプレート ポリシーを受け入れるクラスを単体テストする正しい方法は何ですか?

4

1 に答える 1

3

非静的メソッドを持つクラスを作成し、そのグローバル インスタンス (またはトレイトで静的) を作成し、トレイト クラスをそれに従わせることはできますか?

したがって、ロブのコメントに触発されたアイデアを明確にするために:

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;

   ...
}

上記はテンプレート化され、ほとんどパターンに変わる可能性があると思います...多分。

于 2012-05-18T18:25:49.027 に答える