首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CEF4Delphi和DUnit

CEF4Delphi和DUnit
EN

Stack Overflow用户
提问于 2018-01-14 09:35:04
回答 1查看 1.3K关注 0票数 2

我正在测试我通过CEF4Delphi在应用程序中通过DUnit创建的几个进程。

以下是复制这一问题的MCVE:

代码语言:javascript
复制
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.

下面是测试用例:

代码语言:javascript
复制
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似乎还没有完全初始化。我也尝试了托马西的建议,但这也不起作用。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-14 13:55:32

您的测试不可能以当前的形式通过。铬的装载是延迟的,并且只会在将来的某个时候被加载。然而,您的测试立即检查它是否已加载。测试异步代码是可能的,但它确实会使测试变得一团糟。我要提醒你要小心你正在测试的东西。您可能希望在页面行为测试中使用Selenium这样的另一个工具,并将Delphi测试的重点放在是否在所需的情况下加载正确的页面。

粗略地看一看CEF4演示代码,就会发现创建可能被延迟的原因。

在创建任何浏览器之前,GlobalCEFApp.GlobalContextInitialized必须是真的。如果它尚未初始化,我们将使用一个简单的计时器稍后创建浏览器。

警告:全局状态会破坏单元测试。您需要进一步研究,以确定如何最好地确保您的测试不会受到这种状态的负面影响。

一种可能有效的方法是确保在开始运行任何测试之前初始化GlobalCEFApp.GlobalContextInitialized。但我怀疑这将是一个非常有限的解决方案,因为虽然我不熟悉TChromiumWindow组件,但我怀疑它的许多交互都是异步的。您可以触发一些东西,但随后必须等待事件回调才能确定最终结果。

这就是您的测试代码将变得混乱的地方。例如,假设表单的目的是在铬窗口完全初始化后立即自动加载特定页面。您的测试必须做以下工作:

代码语言:javascript
复制
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。

下面的一些东西应该能起作用。

代码语言:javascript
复制
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...方法添加一个超时参数,如果等待超时意外的话,测试会立即失败。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48248267

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档