我正在测试我通过CEF4Delphi在应用程序中通过DUnit创建的几个进程。
以下是复制这一问题的MCVE:
unit MyUnit;
interface
{$I cef.inc}
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
uCEFWindowParent,
uCEFChromiumWindow,
uCEFChromium,
Vcl.ExtCtrls,
Vcl.StdCtrls;
type
TForm1 = class(TForm)
ChromiumWindow1: TChromiumWindow;
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure ChromiumWindow1AfterCreated(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
FChromiumCreated: Boolean;
procedure WMMove(var aMessage: TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage: TMessage); message WM_MOVING;
public
{ Public declarations }
function IsChromiumCreated: Boolean;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.ChromiumWindow1AfterCreated(Sender: TObject);
begin
ChromiumWindow1.LoadURL('https://www.google.com');
FChromiumCreated := True;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FChromiumCreated := False;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
if not (ChromiumWindow1.CreateBrowser) then
Timer1.Enabled := True;
end;
function TForm1.IsChromiumCreated: Boolean;
begin
Result := FChromiumCreated;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
if not (ChromiumWindow1.CreateBrowser) and not (ChromiumWindow1.Initialized) then
Timer1.Enabled := True
end;
procedure TForm1.WMMove(var aMessage: TWMMove);
begin
inherited;
if (ChromiumWindow1 <> nil) then
ChromiumWindow1.NotifyMoveOrResizeStarted;
end;
procedure TForm1.WMMoving(var aMessage: TMessage);
begin
inherited;
if (ChromiumWindow1 <> nil) then
ChromiumWindow1.NotifyMoveOrResizeStarted;
end;
end.下面是测试用例:
unit TestMyTest;
{
Delphi DUnit Test Case
----------------------
This unit contains a skeleton test case class generated by the Test Case Wizard.
Modify the generated code to correctly setup and call the methods from the unit
being tested.
}
interface
uses
TestFramework,
Vcl.Forms,
MyUnit,
System.Classes;
type
// Test methods for class TForm1
TestTForm1 = class(TTestCase)
strict private
FFormHolder: TForm;
FForm1: TForm1;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestFormActivate;
end;
implementation
procedure TestTForm1.SetUp;
begin
Application.Initialize;
FForm1 := TForm1.Create(nil);
Application.Run;
end;
procedure TestTForm1.TearDown;
begin
FForm1.Free;
FForm1 := nil;
end;
procedure TestTForm1.TestFormActivate;
begin
FForm1.Show;
CheckTrue(FForm1.IsChromiumCreated);
end;
initialization
// Register any test cases with the test runner
RegisterTest(TestTForm1.Suite);
end.如果我使用.Show,则不执行FChromiumCreated := True;指令,TChromium不加载页面,测试返回false。我不确定,但这可能是因为TChromium是异步初始化的,并且在执行测试时,TChromium还没有被完全初始化。
在这种情况下如何执行我的测试?
编辑我读过这个答案。在我的例子中,.Show确实允许进入下一行的测试,但是在那个阶段,TChromium似乎还没有完全初始化。我也尝试了托马西的建议,但这也不起作用。
发布于 2018-01-14 13:55:32
您的测试不可能以当前的形式通过。铬的装载是延迟的,并且只会在将来的某个时候被加载。然而,您的测试立即检查它是否已加载。测试异步代码是可能的,但它确实会使测试变得一团糟。我要提醒你要小心你正在测试的东西。您可能希望在页面行为测试中使用Selenium这样的另一个工具,并将Delphi测试的重点放在是否在所需的情况下加载正确的页面。
粗略地看一看CEF4演示代码,就会发现创建可能被延迟的原因。
在创建任何浏览器之前,GlobalCEFApp.GlobalContextInitialized必须是真的。如果它尚未初始化,我们将使用一个简单的计时器稍后创建浏览器。
警告:全局状态会破坏单元测试。您需要进一步研究,以确定如何最好地确保您的测试不会受到这种状态的负面影响。
一种可能有效的方法是确保在开始运行任何测试之前初始化GlobalCEFApp.GlobalContextInitialized。但我怀疑这将是一个非常有限的解决方案,因为虽然我不熟悉TChromiumWindow组件,但我怀疑它的许多交互都是异步的。您可以触发一些东西,但随后必须等待事件回调才能确定最终结果。
这就是您的测试代码将变得混乱的地方。例如,假设表单的目的是在铬窗口完全初始化后立即自动加载特定页面。您的测试必须做以下工作:
procedure TestTForm1.TestBrowserLoad;
begin
FForm1.InitialPage := 'https://google.com';
FForm1.Show;
WaitForChromiumCreated(Form1.ChromiumWindow1); { <-- This is the tricky bit }
CheckTrue(FForm1.IsChromiumCreated);
end;本质上,WaitForChromiumCreated必须允许主窗体的消息循环继续发送消息。但也会在测试方法中阻止处理。它还需要可靠地知道组件何时完全初始化。在这种情况下,ProcessMessages()是合理的,因为您无法重新构建CEF4。
下面的一些东西应该能起作用。
procedure WaitForChromiumCreated(AChromiumWindow: TChromiumWindow);
begin
while True do
begin
if (AChromiumWindow.Initialized) then Break;
{ You'll also need a way to break out of this loop
if something goes wrong and the component cannot
initialise, or if the tests are aborted. }
Application.ProcessMessages();
end;
end;提示:,我还强烈建议向所有Wait...方法添加一个超时参数,如果等待超时意外的话,测试会立即失败。
https://stackoverflow.com/questions/48248267
复制相似问题