ShowModal
;を呼び出してモーダルフォームをテストすることはできません。なぜなら、あなたが非常に正しく発見したように、モーダルフォームがユーザーの操作を待っている間、テストケースコードが「一時停止」する結果になるからです。
ShowModal
これは、フォームが閉じるまで終了しない「セカンダリメッセージループ」に切り替わるためです。
ただし、モーダルフォームは引き続きテストできます。
- 通常の方法を使用して、通常のモーダルフォームを表示します。
Show
- これにより、テストケースコードを続行し、ユーザーアクションをシミュレートできます。
- これらのアクションと効果は、通常どおりテストできます。
- モーダルフォームに非常に特有の追加のテストが必要になります。
- モーダルフォームは通常、モーダル結果を設定することで閉じられます。
- 使用したという事実は
Show
、モーダル結果を設定してもフォームが閉じられないことを意味します。
- 「OK」ボタンのクリックをシミュレートする場合は、これで問題ありません。
ModalResult
が正しいことを簡単に確認できます。
警告
この手法を使用して、特定のモーダルフォームを非モーダルで明示的に表示することにより、特定のモーダルフォームをテストできます。ただし、モーダル形式(エラーダイアログなど)を示すテスト対象のコードは、テストケースを一時停止します。
サンプルコードでさえClick ('OpenConfigButton');
、ShowModalが呼び出され、その方法でテストすることはできません。
これを解決するには、「showコマンド」をアプリケーションに挿入できるようにする必要があります。依存性注入に慣れていない場合は、YouTubeで入手できるMiskoHeveryのCleanCodeTalksビデオをお勧めします。次に、テスト中に、モーダルフォームを表示しない適切なバージョンの「showコマンド」を挿入します。
たとえば、[OK]ボタンがクリックされたときに検証が失敗した場合、モーダルフォームにエラーダイアログが表示されることがあります。
それで:
1)エラーメッセージを表示するためのインターフェイス(または抽象基本クラス)を定義します。
IErrorMessage = interface
procedure ShowError(AMsg: String);
end;
2)テストしているフォームは、インターフェース(FErrorMessage: IErrorMessage
)への挿入された参照を保持し、検証が失敗するたびにエラーを表示するためにそれを使用できます。
procedure TForm1.OnOkClick;
begin
if (Edit1.Text = '') then
FErrorMessage.ShowError('Please fill in your name');
else
ModalResult := mrOk; //which would close the form if shown modally
end;
3)本番コードに使用/挿入されたデフォルトバージョンのIErrorMessageは、通常どおりメッセージを表示します。
4)テストコードは、テストが一時停止されるのを防ぐために、モックバージョンのIErrorMessageを挿入します。
5)これで、通常はエラーメッセージが表示されるケースをテストで実行できるようになりました。
procedure TTestClass.TestValidationOfBlankEdit;
begin
Form1.Show; //non-modally
//Do not set a value for Edit1.Text;
Click('OkButton');
CheckEquals(0, Form1.ModalResult); //Note the form should NOT close if validation fails
end;
6)模擬IErrorMessageをさらに一歩進めて、メッセージテキストを実際に確認できます。
TMockErrorMessage = class(TInterfaceObject, IErrorMessage)
private
FLastErrorMsg: String;
protected
procedure ShowError(AMsg: String); //Implementaion trivial
public
property LastErrorMsg: String read FLastErrorMsg;
end;
TTestClass = class(TGUITesting)
private
//NOTE!
//On the test class you keep a reference to the object type - NOT the interface type
//This is so you can access the LastErrorMsg property
FMockErrorMessage: TMockErrorMessage;
...
end;
procedure TTestClass.SetUp;
begin
FMockErrorMessage := TMockErrorMessage.Create;
//You need to ensure that reference counting doesn't result in the
//object being destroyed before you're done using it from the
//object reference you're holding.
//There are a few techniques: My preference is to explicitly _AddRef
//immediately after construction, and _Release when I would
//otherwise have destroyed the object.
end;
7)これで以前のテストは次のようになります。
procedure TTestClass.TestValidationOfBlankEdit;
begin
Form1.Show; //non-modally
//Do not set a value for Edit1.Text;
Click('OkButton');
CheckEquals(0, Form1.ModalResult); //Note the form should NOT close if validation fails
CheckEqulsString('Please fill in your name', FMockErrorMessage.LastErrorMsg);
end;