12

私はC++のテストコードから保護されたメンバー関数にアクセスするための最良の方法を考えようと頭を悩ませてきました。これが私の問題です。

//in Foo.h 
Class Foo
{
protected:
    void DoSomething(Data data);
}

//in Blah.h
Class Blah
{
public:
    Foo foo;
    Data data; 
};

//in test code...
Blah blah;
blah.foo.DoSomething(blah.data); // Here's my problem!

これまでのいくつかの可能な解決策:

  • テストコードクラスをFooの友達にしますが、これはFooをテストコードで汚染します
  • DoSomethingをパブリック関数にする
  • この投稿で提案されているように、Fooのテストラッパーを作成することを検討しましたが、BlahにはFooのインスタンスが含まれているため、これは機能しません。

    すべてのアドバイス/洞察/意見は大歓迎です!

    ありがとう

  • 4

    8 に答える 8

    18

    規格で完全に許可されている方法があります。

    //in Foo.h 
    class Foo
    {
    protected:
        void DoSomething(Data data);
    };
    
    //in Blah.h
    class Blah
    {
    public:
        Foo foo;
        Data data; 
    };
    
    //in test code...
    struct FooExposer : Foo {
      using Foo::DoSomething;
    };
    
    Blah blah;
    (blah.foo.*&FooExposer::DoSomething)(blah.data);
    

    説明については、C++エントリの非表示機能をお読みください。


    便宜上、マクロを作成できます(括弧は、このマクロを、のようにコンマを含む型にも使用できるようにするためにありますvector<pair<A, B>>)。

    #define ACCESS(A, M, N) struct N : get_a1<void A>::type { using get_a1<void A>::type::M; }
    
    template<typename T> struct get_a1;
    template<typename R, typename A1> struct get_a1<R(A1)> { typedef A1 type; };
    

    問題は今になります

    ACCESS((Foo), DoSomething, GetDoSomething);
    Blah blah;
    (blah.foo.*&GetDoSomething::DoSomething)(blah.data);
    
    于 2009-11-12T20:24:23.160 に答える
    8

    さて、あなたはそれが単なるテストコードであると言ったので、私は真剣にハッキーな何かを提案するつもりですが、うまくいくでしょう:

    struct tc : protected Foo
    {
        tc(Foo *foo, Data& data)
        {
            ((tc*)foo)->DoSomething(data);
        }
    };
    
    Blah blah;
    tc t(&blah.foo, blah.data);
    
    于 2009-11-12T17:52:37.753 に答える
    7

    一方では、それをしないでください

    一方、ここにギャンブルがあります:

    #define protected public
    #include "foo.h"
    #undef protected
    

    8-)

    しかし、真剣に、なぜDoSomething()保護されているのですか?おそらく、外部コードから呼び出すと何かが壊れる可能性があるためです。その場合、テストからそれを呼び出すべきではありません。

    于 2009-11-12T17:34:56.077 に答える
    3

    終わったよ

    class Foo
    {
    protected:
        void DoSomething(Data data);
    public:
        #ifdef TEST
        void testDoSomething(Data data);
        #endif
    }
    

    次に、g ++-DTESTを使用して単体テストをコンパイルします。

    于 2009-11-12T17:44:06.040 に答える
    3

    ifdefing privatetopublicではなく、ifdefing friendshipを検討するか、その関数が本当にそのクラスに属する必要があるかどうかを考えてください。cppの名前付き/名前なしの名前空間に何かを入れて、テストプロジェクトで宣言するだけで十分かもしれません

    とにかく、このリンクを確認してください。おそらく、テストフレームワークが同様の機能を提供するでしょう。

    編集:実際のクラスからテストクラスを継承することを検討しましたか?

    于 2009-11-12T17:46:49.203 に答える
    2

    次のようにラッパーを使用します。

    // Foo.h unchanged
    
    // Blah.h unchanged
    
    // test code
    class FooTest : public Foo { friend void test(); }; // make friends
    
    void test()
    {
        Blah blah;
        static_cast<FooTest*>(&blah.foo)->DoSomething(blah.data); // Here's no problem!    
    }
    
    于 2009-11-12T19:51:25.983 に答える
    2

    転送機能で継承を使用できます。

    class Foo
    {
    protected:
        void DoSomething(Data data);
    }
    
    class test_Foo : public Foo
    {
    public:
        void testDoSomething(Data data)
        {
            DoSomething(data);
        }
    }
    
    于 2009-11-12T19:40:05.700 に答える
    1

    厳密にテストコードであれば、次のことができます...

    #define protected public
    #include "Foo.h"
    
    // test code
    
    #undef protected
    
    于 2009-11-12T17:36:15.120 に答える