DUnitでプライベートメソッドをテストするにはどうすればよいですか?
-
05-07-2019 - |
質問
DUnitを使用して単体テストを行うクラスがあります。 いくつかのパブリックメソッドとプライベートメソッドがあります。
type
TAuth = class(TDataModule)
private
procedure PrivateMethod;
public
procedure PublicMethod;
end;
このクラスの単体テストを作成するには、すべてのメソッドを公開する必要があります。
プライベートメソッドを宣言する別の方法があるので、まだテストできますが、それらはパブリックではありません。
解決
それらを公開する必要はありません。保護されます。次に、単体テスト用のクラスをサブタイプ化し、保護されたメソッドを表示できます。例:
type
TAuth = class(TDataModule)
protected
procedure MethodIWantToUnitTest;
public
procedure PublicMethod;
end;
今、あなたはあなたのユニットテストのためにサブタイプすることができます:
interface
uses
TestFramework, Classes, AuthDM;
type
// Test methods for class TAuthDM
TestAuthDM = class(TTestCase)
// stuff
end;
TAuthDMTester = class(TAuthDM)
public
procedure MethodIWantToUnitTestMadePublic;
end;
implementation
procedure TAuthDMTester.MethodIWantToUnitTestMadePublic;
begin
MethodIWantToUnitTest;
end;
ただし、ユニットテストを行うメソッドがデータモジュールと密接に関係しているため、プライベート以外のものを使用するのは安全ではない場合、必要なコードを分離するためにメソッドをリファクタリングすることを検討する必要があります単体テスト対象であり、データモジュールの内部にアクセスするコード。
他のヒント
これは少しハッキーですが、これは最も単純で明確なアプローチだと思います。次の条件付きコンパイルディレクティブを使用します。
{$IfNDef TEST}
private
{$EndIf}
ユニットテストプロジェクトは、 project→でTESTを定義する必要があります。条件定義
。可視性の仕様がなければ、それらは公開されます。
注意:プライベート可視性がクラス宣言の最初の可視性でない場合、以前の定義を取得します。より安全な方法ですが、より冗長で明確ではありません:
private
{$IfDef TEST}
public
{$EndIf}
これには、サブクラス化や他のアプローチよりも多くの利点があります:
- 余分な複雑さなし:コードに余分なクラスはありません。
- 誰も「誤解」することはできませんサブクラスを作成してクラスをオーバーライドします。アーキテクチャを保持します。
- メソッドが保護されていると言うとき、あなたはそれが幾分オーバーライドされることを期待します。あなたはあなたのコードを読んでいる人のためにこれを言っています。オーバーライドされるべきではない保護されたメソッドは、コードリーダーを混乱させ、私の最初のプログラミングの原則を破ります。"他の人間が読むにはコードを書く必要があります。"
- DUnitは独自のユニットにあり、どこにも含まれていません。
- 面倒なRTTIに触れないでください。
より明確なソリューションであり、選択した回答よりも優れていると思います。
これを使用するとき、ビルドプロジェクトをメインプロジェクトの別のディレクトリに配置するようにテストプロジェクトも構成します。これにより、TESTディレクティブを含むバイナリが他のコードと混ざることを防ぎます。
" XUnitテストパターン"をお勧めします。ジェラルド・メザロスの本:
質問:コードの作り方 アクセスする必要があるときにテスト可能 SUTのプライベート状態?
回答:を公開するメソッドを追加します テストに必要な状態または動作 SUTのサブクラスに。
...テスト対象のシステム(SUT)が テスト可能なように特別に設計された、 テストが取得できないことがあります しなければならない状態へのアクセス ある時点で初期化または検証する テスト。
この記事では、いつ使用するか、どのリスクを伴うかについても説明しています。
ユニット内にDUnitコードを配置します。その後、好きなものにアクセスできます。
一般に、このような状況に陥ると、私は単一の責任原則に違反していることにしばしば気付きます。もちろん、私はあなたの特定のケースについて何も知りませんが、プライベートメソッドは独自のクラスにあるべきであるかもしれません。 TAuthは、プライベートセクションにこの新しいクラスへの参照を持ちます。
拡張RTTI (Delphi 2010以降)では、RTTIを介してプライベートメソッドを呼び出すことも別のオプションです。このソリューションは、プライベートメソッド、フィールド、または内部クラスを持つクラスをテストするにはどうすればよいですか
{$IFNDEF UNITEST}
private
{$ENDIF}
簡単なソリューション。ほとんどハックではありません。私は頻繁にプライベートメソッドをテストする必要があり、このテクニックはできるだけ複雑さを追加しません。