13

UnitTest ++を使用して単体テストをコーディングするときに、厄介な問題に直面しています。プライベートメンバークラスのフィールドにクリーンな方法で(またはおそらく何らかの方法で)アクセスする方法を考えています...)

これまでに、テスト対象のクラスから派生したクラスフィクスチャを使用して保護されたメンバーにアクセスするソリューションがあります。次のコードはアイデアを示しています。

struct MyFixture : ClassUnderTest { };

TEST_FIXTURE(MyFixture, OneTest)
{
    do_something();
    CHECK(protected_field == true);
}

それでも、一部の構成では継承に関連する問題が発生する可能性があり、とにかく、保護されたメンバーだけにアクセスしてテストできるため、これはあまりクリーンではないと思います。

テストクラスを友達として宣言しようとしましたが、UnitTest ++によって特別な方法で作成されているため、まだそれを行うことができませんでした。

テストクラスをテスト中のクラスの友達にする方法を知っている人はいますか?

この問題にもっと簡単に、または別の方法で取り組む別の方法はありますか?

よろしくお願いします。

4

6 に答える 6

13

ユニットテストによく使用する、本当に醜いが驚くほど便利なハックが1つあります。

#define private public
#define protected public

#include "class_to_be_tested.h"

// and here, all class's methods and fields are public :P

ユニットテスト以外の目的で使用しないでください。

また、このメソッドにはいくつかの制限があります。まず、すべてのプライベートのプレフィックスが。であるとは限りませんprivate。次に、人気のあるコンパイラの1つが、アクセス指定子をリンカーシンボルに変換します。

もう1つの、あまり良くない方法は、キャストを使用することです。同じフィールドを持ち、すべてパブリックである構造を作成し、それをプライベート構造へのポインターにキャストします。ただし、これには、クラスが正確に一致する必要があるという欠点があります。

class my_class
{
private:
   char name[40];
   char grade;
   int age;
public:
   //
}

struct my_class_hack
{
public:
   char name[40];
   char grade;
   int age;

}

struct hack_it* my_class_hacked = (my_class_hack*)ptr;

...ただし、コンパイラがコードをいじくり回すと、厄介な驚きを感じる可能性があるため、これを本番コードに使用しないでください。

于 2010-01-18T11:12:32.180 に答える
6

単体テストとは、パブリックインターフェイスを介してオブジェクトをテストすることです。難しいかもしれないという事実は、テスト可能なコードを書くことが時々アートと呼ばれる理由です。誰もがすぐにテスト可能なコードを書くことができるわけではありません。そのため、人々は最初にテストを書くというXPアプローチを発明しました。非現実的に聞こえますが、実際に機能します。

ただし、どうしてもプライベート関数をテストする必要がある場合は、次の方法を自分の好みの順に検討します。

  1. プライベートメンバー変数には、パブリックセッターとゲッターを介してアクセスします。

  2. プライベートメンバー関数を、egまたは。と呼ぶことができる名前空間内の非静的非メンバー関数にすることをお勧めします。ヘッダーファイルで宣言するのではなく、クラス関数が定義されているのと同じファイルで定義するだけです。その宣言を単体テストプロジェクトのヘッダーファイルに追加してテストします。関係する問題は、アーキテクチャの複雑さに大きく依存します。detailsinternalmyClass_internal.h

  3. テストクラスをテスト可能なクラスから継承させます。これにはコードの変更はあまり含まれませんが、多重継承の使用が必要になる場合があり、場合によっては禁止されています。

  4. テストをテスト可能なクラスの友達にします。難易度は、使用しているテストフレームワークによって異なります。言ってやるが、私が使っているgtestでは、かなり難しい:)

  5. 他のすべてが失敗した場合、パブリックとプライベートを再定義するハックは絶対に最後の手段になるはずです。代わりに、デザインをよりテスト可能なものに変更することを考えたいと思いますが。

于 2010-01-18T15:46:06.077 に答える
4

#defineHackにも行きます。

ただし、#defineクラス構造体を配置して、暗黙のプライベートクラスデータも公開します。

私はドミトリーに反対しなければなりません:

1.)これにより、テストのためだけに本番コードにインターフェイスが追加され、カプセル化に違反します。クライアントに私の個人データへのアクセスを許可したくない

2.)再び1.)に見られるように->これらのインターフェースが実際にテストのためにのみ公開されている場合は、良い考えです

3.)アクセスが保護されている場合にのみ機能します。これにより、カプセル化も不可能になります。

4.)また、テストのためだけに本番コードを変更することを意味し、本番コードとテストコードの間にカップリングを作成することさえあります!!!

5.)あなたの観点からすると、それは正しいです、私は醜い本番コードよりも醜いテストコードを持っています:)

于 2010-01-18T17:05:56.940 に答える
4

これは数年前に熱い議論の対象でしたが、一般的に受け入れられている結果は、クラスの外部から見える動作のみをテストする必要があるため、内部データと動作へのアクセスは必要ありません。

これは最初は役に立たないように聞こえるかもしれませんが、テストするクラスのプライベート部分を、外部の動作テストする動作である新しいクラスに抽出することができます。その後、これらのクラスを通常の方法でテストでき、全体的な設計が改善されます。

于 2010-01-18T11:12:31.923 に答える
1

「そんなことはしないでください」と言う人には同意しますが、テスト対象のクラスに必要なすべての変更を加える自由がない大規模なプロジェクトで作業している場合があります。そのような状況では、私は公的/私的再定義ハッカリーよりも友人宣言を好むでしょう。

UnitTest ++でそれを行う方法を理解しました。これ は、「Internals」テストから使用したい「dealInternal」保護/プライベートメソッドを持つ「Deck」クラスの例です。

    //------------- Deck.h -------------
    namespace SuiteDeck { class TestInternals; }

    class Deck {
        // etc...
        private:
        friend class SuiteDeck::TestInternals;
        bool dealInternal();
    };

    //------------ TestDeck.cpp ----------
    #include "UnitTest++.h"
    #include "Deck.h"

    SUITE(Deck) {
        TEST(Internals) {
            Deck d;
            CHECK(d.dealInternal() == true); // or whatever
        }
    }
于 2011-07-19T18:12:52.533 に答える
0

個人的なものをテストすることは避けたほうがいいです。なぜprivate_fieldをテストしたいのですか?private_fieldが無効な値に設定されていると何が問題になりますか?間違った値を主張する代わりに、この間違った動作をテストすることは可能ですか?

その他のオプションは次のとおりです

  • 単体テスト用にコードをコンパイルするときにプリプロセッサを試して公開します

  • プライベートフィールドと関連するロジックを新しいクラスに抽出し、そこでパブリックにし、ClassUnderTestをこの新しいクラスに依存させます。

于 2010-01-18T11:14:29.667 に答える