在delphi中访问其他.exe数据的最简单方法是什么?

时间:2013-02-04 20:00:07

标签: delphi ipc automated-tests dunit

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

所以我需要两个:

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

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

如果我将错误的项目创建为测试过程的子过程,启动代码运行正常,但我找不到一种方法来调用导出的函数,而无需复杂的IPC方法或对坏项目结构进行实质性更改。

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

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

我怎么能两个都做?

2 个答案:

答案 0 :(得分: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的内部和专有。但它确实说明该方法确实有效,并且不需要重写整个应用程序或编写大量的模拟类,如单元测试 会做。如果你想沿着黑客路线前进,你将编写自己的用户界面测试框架,它应该完全独立于,不使用DUnit代码。欢迎您尝试,但我告诉您,这是一个严重的阻抗不匹配。如果我在2013年开始自己的自定义框架,它将基于DCOM,因为Delphi DCOM服务器代码可以简单地有条件地编译成许多程序,DCOM将为您处理函数调用“编组”细节。我怀疑我会进入项目一年,我会放弃,因为最后,我怀疑我可以使任何系统(基于DCOM或Win32消息)得到回报。

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

答案 1 :(得分: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_条件定义时,我必须首先登录,以便初始化我们的应用程序(和数据库连接)。关注了DUn的GUITestrunner。

测试用例可以在初始化部分中注册,与示例完全相同。

像魅力一样。