2

我尝试使用 Delphi 2010 附带的 DUnit 对 1000 万个 LOC 项目实施一些基本的自动化测试,这些项目不遵循良好的 OO 实践(例如:将业务逻辑隔离到类/单元中)。我不能做正常的单元由于业务逻辑的每个部分都分布在数十个相互依赖的单元中,因此在该项目上进行测试,但是这些单元“组”以某些“主要业务逻辑屏幕”为中心(例如:所有与发票逻辑相关的单元都以主发票屏幕),并且由于这些屏幕是类,我可以进行“主要业务逻辑屏幕类测试”而不是单元测试,但是这些“主屏幕”仍然需要在流程启动期间创建的很多东西。

所以我需要两者:

  • 能够运行坏项目的启动内​​容
  • 能够访问其对象

坏项目已经有一些导出的函数返回指针,我可以转换它们来访问它的对象,但我无法以任何一种方式调用它们:

如果我将坏项目创建为测试进程的子进程,启动代码运行良好,但如果没有复杂的 IPC 方法或对坏项目的结构进行实质性更改,我找不到调用导出函数的方法。

如果我像 LoadLibrary 函数一样将坏项目的 .exe 作为 dll 加载,调用坏项目导出的任何函数都会导致访问冲突和/或段错误,即使是这个简单的过程:

procedure Test; {safecall;} {stdcall;}
begin
  showmessage('Yay!');
end;

我怎样才能做到这两点?

4

2 回答 2

3

您正在谈论的方法(使用导出的函数)不会成功。两个 Win32 程序之间最简单的通信形式是让它们使用 SendMessage 或 PostMessage 相互通信。定位窗口句柄(通常通过窗口类名)是第 1 步,发送消息是第 2 步。

其次,DUnit 让你离你的目标很远,而且 TTestCase 不能巧妙地扩展为一个 GUI 控制器,因为这不是它的用途。它用于单元测试。圆钉,方孔。为您可以配置和测试的类编写 TTestCases,并使用 DUnit 为您可以为其提供测试覆盖的系统部分提供测试覆盖。

对于 UI 测试,请使用完全独立的框架。Delphi 程序员为您提议的那种自动集成测试完成了两种基本方法。

  1. 一个自定义的黑客工作。这就是你所描述的。在 Embarcadero 内部,存在一个名为Zombie的框架,这是 Nick 在 2007 年发表的博客。它的方法基于几种“原始 IPC”,通常涉及从程序外部到程序内部控件的窗口句柄的 Win32 SendMessage 或 PostMessage 窗口消息。然而,内部代码被显着修改以允许僵尸测试。不,你不能拥有 Teh Codez,它们是 Embarcadero 内部和专有的。但它确实说明了该方法确实有效,并且不需要像单元测试那样重写整个应用程序或编写大量模拟类。如果您想走 hack 路线,您将编写自己的用户界面测试框架,它可能应该完全独立于并且不使用 DUnit 代码。欢迎你尝试,但我告诉你,它' sa 严重的阻抗失配。如果我在 2013 年开始我自己的自定义框架,它将基于 DCOM,因为 Delphi DCOM 服务器代码可以简单地有条件地编译成许多程序,并且 DCOM 会为您处理函数调用“编组”细节。我怀疑我会在这个项目中投入一年,然后我会放弃,因为最后,我怀疑我能否让任何系统(基于 DCOM 或 Win32 消息)得到回报。

  2. 一个完整的外部测试工具,您可以在其中编写测试脚本,例如 AutomatedQA/SmartBear TestComplete。您的测试不会被编译成 delphi 测试程序,而是在 TestComplete 中运行,类似 Pascal 的脚本语法只是编写测试脚本的可用选项之一。

于 2013-02-04T21:13:47.377 回答
1

我们在这里遇到了同样的问题。看起来您确实需要一个 delphi 库项目 (*.dll) 才能使导出函数工作,(我怀疑直接在可执行文件上调用函数时不会初始化框架,没有保证)。

注意:我们仍在使用 Delphi 5,所以这里没有 dunit 集成。

我们使用的解决方案是使用条件 DEFINE 将 dunit 源添加到我们的项目(.exe 项目)中,并在启动单元中使用此条件定义。

我们应用程序的示例启动代码:

  if ComServer.StartMode <> smAutomation then
  begin
    OurApplication.Login ;
  end;
{$IFDEF _AS_TESTRUNNER_}
    GUITestRunner.RunRegisteredTests;
{$ELSE}

  if OurApplication.HasStartCommands then
  begin
    Application.ShowMainForm := False ;
  end
  else begin
    if ComServer.StartMode = smAutomation then
      Application.ShowMainForm := False
  end;

  Application.Run;
{$ENDIF}

  OurApplication.Finalize;

当我使用 _AS_TESTRUNNER_ 条件定义时,我必须先登录,以便我们的应用程序(和数据库连接)被初始化。跟随 bij DUnit 的 GUITestrunner。

测试用例可以在初始化部分注册,就像在示例中一样。

奇迹般有效。

于 2013-02-21T17:03:13.037 回答