現在、TDDなしで作成された既存のデザインをリファクタリングしています。 1つの抽象基本クラスと2つのサブクラスを持つクラス階層があります。元の設計では、これらのクラスはほとんど動作を持たない単なるデータホルダーでした。基本クラスに実装する必要があるいくつかの機能を特定しました。この機能のテストを今すぐ作成します。しかし、クラスは抽象であるため、インスタンス化できません(明らかに)。
注:テストしたい機能は、pure virtual
メソッドを呼び出しません。
class Base {}; // Is abstract
TEST(BaseTest, doesSomethingAmazing) {
Base aBase; // <-------- Not possible!!!
ASSERT_THAT(aBase.amazeMe(), Eq(AMAZING_RESULT));
}
編集:いくつかのことを明確にするために:
私はいくつかの可能な解決策を考えることができますが、それらのどれも私にとって最適ではないようです:
pure virtual
関数を実装するサブクラスをテストコードに追加します。欠点:サブクラスに簡潔な名前を付けるのは難しく、テストの理解が難しくなります。私はテストをできるだけ明確にするためにオプション3を選ぶ傾向がありますが、私はそれで本当に満足していません。私が知らないもっと良い方法はありますか?
テストする機能が純粋な仮想メソッドを呼び出さず、サブクラスでオーバーライドされない限り、箇条書きの番号1を使用して、テスト固有のサブクラスを作成します。 Sub<ClassName>
またはサブクラス自体が重要ではないことを反映する一般的な名前。
テストしたいものが最終的な具象クラスによって何らかの方法で変更できる場合は、これを検討する必要があるかもしれません。
使用しているC++テストフレームワークに同等のものがあるかどうかはわかりませんが、 NUnit (およびJUnit)では Abstract Test パターンを実装できます。
要するに、あなたは持っています
抽象基本テストクラス。テスト対象オブジェクトの生成に使用される抽象ファクトリメソッドと、テストメソッド自体が含まれています。これらのメソッドは、その下にある具体的なオブジェクトに関係なく、真でなければならないことを検証します。
テスト中の抽象クラスの派生物と同じ数の派生テストクラス。ここでファクトリメソッドを実装して、派生クラスのインスタンスを返すだけです。
テストランナーは、派生テストクラスを確認すると、ファクトリメソッドで生成されたオブジェクトに対して、基本テストクラスから継承したすべてのテストメソッドを自動的に実行します。
次のことができます。
AmazingObjectInterface
)。BasicAmazingObject
というサブクラスを追加します。BasicAmazingObject
のサブクラスになります。これにより、変化するものを分離し、必要なものを適切にテストできます。もちろん、yoはもう1つのクラスを導入しますが、これはC++での(Javaの意味での)インターフェースサポートの欠如に対する代償)です。