web-dev-qa-db-ja.com

プライベートメソッドの単体テスト

私はいくつかの単体テストを書いています。特に、いくつかのプライベートメソッドをテストしたいと思います。

これまでのところ、私は使用することを考え出しました。

#define private public

しかし、単体テストの観点からすべてのカプセル化を破壊するため、これには満足していません。

プライベートメソッドの単体テストに使用するメソッド。

90
Mumbles

メソッドが単独でのテストを保証するほど複雑な場合は、メソッドを独自のクラスにリファクタリングし、パブリックインターフェイスを介してテストします。次に、元のクラスでプライベートに使用します。

56
Mike Seymour

厄介な#defineあなたが質問で言及したハック、よりクリーンなメカニズムは、テストをテスト中のクラスの友人にすることです。これにより、テストコード(およびテストコードのみ)がプライベートにアクセスできるようになり、他のすべてからプライベートが保護されます。

ただし、パブリックインターフェイスを使用してテストすることをお勧めします。クラスXのプライベートメンバー関数に多くのコードがある場合、クラスXの実装で使用される新しいクラスYを抽出する価値があります。この新しいクラスYは、公開インターフェイスを介してテストできます。クラスXのクライアントに使用します。

72

Google Testを使用している場合、 FRIEND_TEST を使用して、テストフィクスチャをテスト中のクラスのフレンドとして簡単に宣言できます。

そして、ご存知のとおり、プライベート関数のテストが他の回答のいくつかが言っているように明確に悪い場合、おそらくGoogle Testに組み込まれないでしょう。

プライベート関数のテストが良いか悪いかについては、こちらをご覧ください この回答では

60
jlstrecker

テストクラスを元のクラスのフレンドとして作成します。このフレンド宣言は#define UNIT_TESTフラグ内にあります。

class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

単体テストのために、フラグ-DUNIT_TESTを使用してコードをコンパイルします。これにより、プライベート機能をテストできます。

UNIT_TESTフラグがfalseになるため、単体テストコードは運用環境にプッシュされなくなります。したがって、コードはまだ安全です。

また、単体テスト用の特別なライブラリは必要ありません。

30
Manoj R

これは古い質問ですが、私が好む比較的良い方法を誰も共有していないようです。

テストするメソッドをprivateからprotectedに変更します。他のクラスの場合、メソッドはprivateのままですが、テストするプライベート機能を公開する基本クラスから「テスト」クラスを派生できます。

最小限の例を次に示します。

class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

もちろん、基本クラスの代わりに派生クラスでテストを実行するには、ユニットテストを更新する必要がありますが、その後、基本クラスに加えられた変更はすべて「テスト」クラスに自動的に反映されます。

13
Miloš

何時間も後、これは私が自分のプライベートな機能をテストしたい人にとって最良のソリューションであると決めたものです。これは、 Max DeLisoMiloš による回答の組み合わせです。

boost :: unit-testを使用している場合、簡単でエレガントなソリューションがあります。

  1. クラスでprotectedの代わりにprivateを使用します

    /* MyClass.hpp */
    
    class MyClass {
    
    protected:
        int test() {
            return 1;
        }
    };
    
  2. フィクスチャを作成します

    /* TestMyClass.cpp */
    
    class F : public MyClass {};
    
    
    BOOST_FIXTURE_TEST_SUITE(SomeTests, F)
    
    // use any protected methods inside your tests
    BOOST_AUTO_TEST_CASE(init_test)
    {
        BOOST_CHECK_EQUAL( test(), 1 );
    }
    BOOST_AUTO_TEST_SUITE_END()
    

このようにして、#define private publicなしで、またはクラスにfriendsを追加せずに、MyClass関数を自由に使用できます!

6
Pari

定義ハックは恐ろしいアイデアです。コードをコンパイルするときにプリプロセッサで任意にコードを書き直すことは賢明ではありません。

すでに数人が言及しているように、プライベートメソッドをまったくテストする必要があるかどうかは議論の余地があります。しかし、これは、インスタンス化を特定のスコープに制限するために意図的にコンストラクターを非表示にした場合や、その他のいくつかの難解な場合には適用されません。

また、名前空間をフレンドすることはできず、「フレンドシップ」はC++に継承されないため、ユニットテストフレームワークによっては問題が発生する可能性があります。幸いなことに、Boost.Testを使用している場合、フィクスチャの形でこの問題に対するエレガントな解決策があります。

http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

フィクスチャをフレンドし、ユニットテスト関数で使用するすべてのインスタンスをインスタンス化して、フィクスチャに対して静的であり、モジュールスコープでインスタンスを宣言することができます。名前空間を使用している場合は心配しないでください。名前空間内でフィクスチャと名前空間外のテストケースを宣言し、スコープ解決演算子を使用して静的メンバーに到達するだけです。

BOOST_FIXTURE_TEST_CASEマクロは、フィクスチャのインスタンス化と分解を処理します。

5
Max DeLiso

プライベートメソッドにはユニットテストケースは必要ないと思います。

メソッドがプライベートの場合、そのクラス内でのみ使用できます。このプライベートメソッドを使用してすべてのパブリックメソッドをテストした場合、これらの多くの方法でのみ使用されているため、個別にテストする必要はありません。

1
aeh