Click ('OpenConfigButton'); Click ('OkButton');
第二次点击仅在模态窗体关闭时执行,我必须手动执行.
我不太了解模态在后台如何工作,但必须有一些方法来规避这种行为.天真地,我想以某种方式在线程中执行ShowModal,以使“主线程”保持响应.现在我知道在一个线程中运行ShowModal可能会弄乱一切.有什么办法吗任何方式来规避ShowModal的阻塞性质?有没有人在Delphi中进行GUI测试?
我了解外部工具(来自QA或其他),我们使用这些工具,但这个问题是关于IDE内的GUI测试.
谢谢!
解决方法
这样做的原因是,ShowModal将切换到“辅助消息循环”,直到表单关闭后才会退出.
然而,模态仍然可以被测试.
>使用正常的Show方法显示通常的模态窗体.
>这允许您的测试用例代码继续,并模拟用户操作.
>这些动作和效果可以正常测试.
>您将需要一个额外的测试,特别是模态形式:
通过设置模态结果通常关闭模态窗体.
>事实上,你使用“显示”表示不会通过设置模态结果来关闭窗体.
>这是很好的,因为如果你现在模拟点击“确定”按钮…
>您可以简单地检查ModalResult是否正确.
警告
您可以使用此技术通过非模态显式显示来测试特定的模态形式.但是,任何显示模态表单的代码(例如“错误对话框”)将暂停您的测试用例.
甚至你的示例代码:点击(‘OpenConfigButton’);导致ShowModal被调用,不能以这种方式进行测试.
要解决这个问题,您需要将“show命令”注入到应用程序中.如果您对依赖注入不了解,我建议您使用Misko Hevery的“清洁代码会话”视频.然后在测试时,您将注入不会显示模态窗体的“show命令”的合适版本.
例如,如果在单击“确定”按钮时验证失败,您的模态窗体可能会显示错误对话框.
所以:
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,以防止您的测试被暂停.
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;