Delphi DUnit无法创建表单。当前没有活动的MDI表单

Delphi DUnit无法创建表单。当前没有活动的MDI表单,delphi,unit-testing,mdi,delphi-xe3,dunit,Delphi,Unit Testing,Mdi,Delphi Xe3,Dunit,嘿,我在Delphi XE3中的单元测试有一个问题我有一个由1个MDIForm和分配的MDIChild表单组成的项目,问题是当我在MDIChild表单上运行测试时,我得到以下错误: TestAllDataSrouces: EInvalidOperation at $0064346F SetUp FAILED: Cannot create form. No MDI forms are currently active 我的安装方法如下所示: procedure TestTCustomerCar

嘿,我在Delphi XE3中的单元测试有一个问题我有一个由1个MDIForm和分配的MDIChild表单组成的项目,问题是当我在MDIChild表单上运行测试时,我得到以下错误:

TestAllDataSrouces: EInvalidOperation
at  $0064346F
SetUp FAILED: Cannot create form. No MDI forms are currently active
我的安装方法如下所示:

procedure TestTCustomerCard.SetUp;
begin
  FCustomerCard :=  TCustomerCard.Create(Application);
end;
如何解决此错误?到目前为止,我试过:

FCustomerCard :=  TCustomerCard.Create(Application.MainForm);

FCustomerCard :=  TCustomerCard.Create(nil);

我的测试是:

procedure TestTCustomerCard.TestAllDataSrouces;
var
  I: Integer;
begin
  for I := 0 to FCustomerCard.ComponentCount-1 do
  begin
    if (FCustomerCard.Components[i] is TcxLookupComboBox) then
    begin
      Check(TcxLookupComboBox(FCustomerCard.Components[i]).Properties.ListSource = nil,'Error no ListSource, Lookup: '+TcxLookupComboBox(FCustomerCard.Components[i]).Name+' Parent: '+TcxLookupComboBox(FCustomerCard.Components[i]).Parent.Name);
    end;
    if (FCustomerCard.Components[i] is TcxDBTextEdit) then
    begin
      Check(TcxDBTextEdit(FCustomerCard.Components[i]).DataBinding.DataSource = nil,'Error No DataSet, Text Edit: '+TcxDBTextEdit(FCustomerCard.Components[i]).Name+' Parent: '+TcxDBTextEdit(FCustomerCard.Components[i]).Parent.Name);
    end;
    if (FCustomerCard.Components[i] is TcxGridDBTableView) then
    begin
      Check(TcxGridDBTableView(FCustomerCard.Components[i]).DataController.DataSource = nil,'Error no Data Source, DB Grid View: '+TcxGridDBTableView(FCustomerCard.Components[i]).Name);
    end;
  end;
end;

演示项目:

错误消息指出了问题所在。如果需要MDI子窗体,则它必须具有MDI父窗体。父窗体必须是程序的主要窗体。在DUnit项目中很难实现。您的解决方案似乎是:

  • 使程序的主窗体成为MDI主窗体。我认为这将是一个棘手的目标
  • 使受测表单不是MDI子表单
  • 找到一种不需要实例化此表单的测试方法
您所做的更像是功能测试或集成测试。您正在检查UI是否正确设置。这种测试不同于单元测试

单元测试应该检查,如果你给一个模块特定的输入,那么它们就会产生特定的输出。单元测试是本地化的。它们旨在独立于其他单元测试单元的行为。UI具体取决于其他单元。它们从输入设备获取数据并在数据库上运行,总体上具有相当复杂的依赖关系。这使得它们成为单元测试的一个坏目标

看看这个问题-


要进行您想要的测试,最好是制作您自己的工具,以正确设置环境并执行测试。

我遇到了同样的问题,我决定实施David Heffernan的建议并“使您的被测表单不是MDI子表单”

在这里,我将描述我是如何做到这一点的。我已经在我的测试用例单元中做了所有更改

  • 生成继承原始MDI子窗体的测试窗体

    类型TTestCustomerCard=类别(TCCustomerCard)结束

    在测试用例类之前添加这个

  • 将dfm文件或表单(如CustomerCard.dfm)复制到TestCustomerCard.dfm

  • 在任何文本编辑器中打开TestCustomerCard.dfm,删除行

    FormStyle=fsMDIChild
    (因为fsNormal是默认值)

    换第一行
    对象客户卡:t客户卡

    对象测试客户卡:TTestCustomerCard

  • 添加指令
    {$R TestCustomerCard.dfm}

  • 在安装方法中,而不是

    fcCustomerCard:=tcCustomerCard.Create(应用程序)

    fcCustomerCard:=TTestCustomerCard.CreateNew(应用程序);
    InitComponents('TTESTCUSTOMERCARD',FCCustomerCard);
    


  • 错误消息解释了问题。没有MDI父窗体。有没有办法在测试中将窗体创建为MDI窗体而不是子窗体?我不理解这个问题。有没有简单的解决方案?DUnit和MDI确实不能很好地混合。你在测试GUI吗,或者您只是将所有业务逻辑与GUI混合在一起了吗?是的,您是对的,我的数据库代码在我的程序中处于较低的级别,我不测试代码,我要测试的是GUI组件属性,以检查DBEdit组件是否有分配给它的数据源,如果没有,则测试失败,因此我基本上测试它的组件赛尔夫,如果你能提供一个解决方案,如何使我的MDI子窗体不是我的DUnit项目中的那样,我会接受你的答案。或者使主窗体成为MDI父窗体,或者子窗体不是MDI子窗体。其实并不是那么简单,我已经尝试了一整天,但运气不好,如果你认为你可以管理它,下载演示项目,它有相同的代码:)为什么我要下载代码,然后试着做你的工作?你问了一个高层次的问题。也许其他人想为您编写代码。这不是我的工作,项目是私人的,我想在Delphi中学习单元测试,我请专业人士帮助我,如果你不想帮我,那很好。嗯,实际上是有道理的:)谢谢,我是这些测试的新手,但随着我的项目进展,我再也无法逃避它们了,因为一个错误的举动和一半的逻辑消失了,或者在我的情况下,我的数据源的一半:我不明白为什么UI不能接受单元测试。是的,它有依赖项,但几乎所有代码都有依赖项。例如,使用mock来处理这个问题。也许AirWolf不想做单元测试。但我不同意你表面上的建议,即UI测试不是单元测试。阅读他对我答案的第一句评论。对我来说,这听起来像是单元测试。@DavidHeffernan称它们为“单元测试”是令人困惑的,因为它们与单元测试的所有常见定义都非常不同。当然,您可以使用单元测试框架来进行功能测试和集成测试,但我认为测试本身不符合单元测试的条件。@jp如果它们是单元测试,我就称它们为单元测试。这里的单元是GUI层。我不是说集成测试。为什么你认为GUI代码不能是一个单元?如果你只测试GUI,你是对的。但事实上,由于事件处理程序中的所有行为等,UI测试在大多数情况下都远远不止测试UI。你真的编写了只测试UI而不测试任何行为并只检查连接的UI测试吗(我很好奇)?正如我自己发现的,这个决定有一个严重的缺点,因为未调用forms OnCreate事件。因此,我决定为我的表单`constructor TCustomerCard.CreateWithAnotherDFM做一个特殊的构造函数<代码>构造函数TCCustomerCard.CreateWithAnotherDFM(所有者:TComponent);开始创建新的(AOOwner);InitComponents('TTESTCUSTOMERCARD',Self);文档创建;结束
    procedure TestTCustomerCard.TestAllDataSrouces;
    var
      I: Integer;
    begin
      for I := 0 to FCustomerCard.ComponentCount-1 do
      begin
        if (FCustomerCard.Components[i] is TcxLookupComboBox) then
        begin
          Check(TcxLookupComboBox(FCustomerCard.Components[i]).Properties.ListSource = nil,'Error no ListSource, Lookup: '+TcxLookupComboBox(FCustomerCard.Components[i]).Name+' Parent: '+TcxLookupComboBox(FCustomerCard.Components[i]).Parent.Name);
        end;
        if (FCustomerCard.Components[i] is TcxDBTextEdit) then
        begin
          Check(TcxDBTextEdit(FCustomerCard.Components[i]).DataBinding.DataSource = nil,'Error No DataSet, Text Edit: '+TcxDBTextEdit(FCustomerCard.Components[i]).Name+' Parent: '+TcxDBTextEdit(FCustomerCard.Components[i]).Parent.Name);
        end;
        if (FCustomerCard.Components[i] is TcxGridDBTableView) then
        begin
          Check(TcxGridDBTableView(FCustomerCard.Components[i]).DataController.DataSource = nil,'Error no Data Source, DB Grid View: '+TcxGridDBTableView(FCustomerCard.Components[i]).Name);
        end;
      end;
    end;