jpf*_*ius 13 delphi testing gui-testing delphi-xe
在这篇关于delphiXtreme的有趣博客文章中,我读到了关于DUnit的内置GUI测试功能(基本上是TGUITestCase在单元GUITesting中定义的替代测试用例类,其具有用于在GUI中调用动作的若干实用程序功能).我很满意它,直到我发现它不适用于模态形式.例如,如果第一个按钮显示模态配置表单,则以下序列将不起作用:
Click ('OpenConfigButton');
Click ('OkButton');
Run Code Online (Sandbox Code Playgroud)
第二个Click只在模态窗体关闭时执行,我必须手动完成.
我不太了解模态表单在后台如何工作,但必须有一些方法来规避这种行为.天真地,我想以某种方式执行ShowModal"在一个线程中",以便"主线程"保持响应.现在我知道ShowModal在线程中运行可能会搞砸一切.还有其他选择吗?任何方式来规避一个阻止性质 ShowModal?有没有人在Delphi中进行GUI测试的经验?
我了解外部工具(来自QA或其他人),我们使用这些工具,但这个问题是关于IDE中的GUI测试.
谢谢!
Dis*_*ned 22
你不能通过调用来测试模态形式ShowModal; 因为你已经非常正确地发现,这导致你的测试用例代码'暂停',而模态形式等待用户交互.
这样做的原因是ShowModal切换到"辅助消息循环",在表单关闭之前不会退出.
但是,仍然可以测试模态形式.
ShowShow意味着不会通过设置模态结果来关闭表单.ModalResult是否正确.您可以使用此技术通过非模态地显示它来测试特定的模态形式.但是,任何显示模式形式的测试代码(例如错误对话框)都会暂停您的测试用例.
甚至你的示例代码:Click ('OpenConfigButton');导致ShowModal被调用,并且无法以这种方式进行测试.
要解决此问题,您需要将"show命令"注入您的应用程序.如果您不喜欢依赖注入,我建议在You Tube上提供Misko Hevery的Clean Code Talks视频.然后在测试时,注入一个合适版本的"show命令",它不会显示模态形式.
例如,如果单击"确定"按钮时验证失败,则模式窗体可能会显示错误对话框.
所以:
1)定义接口(或抽象基类)以显示错误消息.
IErrorMessage = interface
procedure ShowError(AMsg: String);
end;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
tom*_*azy 11
实际上有一种方法可以在Delphi中测试模态窗口.当显示模态窗口时,您的应用程序仍会处理Windows消息,因此您可以在显示模式窗口之前将消息发布到某个帮助窗口.然后您的消息将从模态循环处理,允许您在模态窗口仍然可见时执行代码.
最近我一直在研究一个简单的库来处理这个问题.您可以从此处下载代码:https://github.com/tomazy/DelphiUtils(请参阅:FutureWindows.pas).
样品用法:
uses
Forms,
FutureWindows;
procedure TFutureWindowsTestCase.TestSample;
begin
TFutureWindows.Expect(TForm.ClassName)
.ExecProc(
procedure (const AWindow: IWindow)
var
myForm: TForm;
begin
myForm := AWindow.AsControl as TForm;
CheckEquals('', myForm.Caption);
myForm.Caption := 'test caption';
myForm.Close();
end
);
with TForm.Create(Application) do
try
Caption := '';
ShowModal();
CheckEquals('test caption', Caption);
finally
Free;
end;
end;
Run Code Online (Sandbox Code Playgroud)