Information in this topic applies to desktop applications only. |
Connected and Self-Testing applications are deprecated. These technologies will be removed in one of the future releases of TestComplete. To create test code that runs from within your tested apps, use TestLeft, a SmartBear functional testing tool for developers. |
This topics explains how you can expose objects of Delphi applications as scripting objects in TestComplete. The explanation applies to applications created using the following compilers:
- Borland Delphi 7.0
- Borland Delphi 2005 and 2006 for Win32
- CodeGear Delphi 2007 and 2009 for Win32
- Embarcadero Delphi 2010 and XE
The topic is divided into the following sections:
Preparing Your Delphi Project
In order for you to expose objects of Delphi applications as TestComplete scripting objects, you need to get access to the TestComplete COM server. The easiest way to manage TestComplete via COM is to transform your application into a Connected Application. Delphi Connected Applications are created by linking the <TestComplete>\Connected Apps\Delphi\TCConnect.pas unit to your project. This unit provide objects and routines that free you from having to manually write the code needed to connect to TestComplete via COM.
For detailed instructions on creating Delphi Connected Applications, see Creating Connected Applications in Delphi.
Creating the Object Type Library
TestComplete can create scripting objects from those objects of Delphi applications that provide type information. So, before creating a custom scripting object and writing its code, you need to create a type library that describes the object’s interface, its methods and properties, their parameters and so on. If you need to expose an existing object of an application (for instance, a specific global or non-visual object), you need to create a COM wrapper that provides access to this object. To learn how you can do this, please refer to the Delphi documentation.
To create a new type library in Delphi, follow these steps:
-
Open your project in Delphi.
-
Choose File | New | Other from Delphi’s main menu. This will call the New Items dialog.
-
In Delphi 7, switch to the ActiveX page of the dialog, select Type Library and press OK.
In Delphi 2005 or 2006 for Win32, select the Delphi Projects | ActiveX category on the left of the dialog, then select Type Library and press OK.
Delphi will create a new type library and show the editor for it.
-
Using the editor, create an interface that defines your scripting object. In our example, we will create an interface containing one read-write property,
Text
, and one method,ShowText
:Tip: Help strings that you specify for methods and properties will be shown as a method (or a property) description in the Code Completion window. -
Select File | Save from Delphi’s main menu.
Delphi will generate the binary type library file (.tlb) and the LibraryName_TLB.pas unit holding the type library implementation. It will also add this unit to your project.
-
Exit the Type Library editor.
Writing the Object Code
After you have defined the object interface, you can create a class that implements this interface and write the implementation of the interface methods and properties. In our example, the Text
property will obtain and return a text string, and the ShowText
method will display this string in a message box.
The class name of our object to be exposed is TSampleRuntimeObject
. We made the object class a descendant of the TAutoIntfObject
class. This is a Delphi class implementing the IDispatch
interface. Since TAutoIntfObject
is defined in the ComObj unit, we include this unit into the uses
clause of the unit. We also included the ActiveX unit there, because it holds the definition of the ITypeLib
interface that provides access to the information on types in a type library (this interface is used in the TSampleRuntimeObject
class constructor).
Delphi
{SampleRuntimeObjectUnit.pas}
unit SampleRuntimeObjectUnit;
interface
uses
Dialogs, ComObj, ActiveX, SampleRuntimeObject_TLB;
type
TSampleRuntimeObject = class(TAutoIntfObject, ISampleRuntimeObjectIntf)
private
FText: WideString;
function Get_Text: WideString; safecall;
procedure Set_Text(const Value: WideString); safecall;
public
constructor Create;
procedure ShowText; safecall;
property Text: WideString read Get_Text write Set_Text;
end;
implementation
function GetTypeLib: ITypeLib;
begin
OleCheck(LoadTypeLib(PWideChar(WideString(ParamStr(0))), Result));
end;
constructor TSampleRuntimeObject.Create;
begin
inherited Create(GetTypeLib, ISampleRuntimeObjectIntf);
FText := '';
end;
function TSampleRuntimeObject.Get_Text: WideString; safecall;
begin
Result := FText;
end;
procedure TSampleRuntimeObject.Set_Text (const Value : WideString); safecall;
begin
FText := Value;
end;
procedure TSampleRuntimeObject.ShowText; safecall;
begin
ShowMessage(FText);
end;
end.
Registering and Unregistering Custom Scripting Objects
In order to add our custom object to the TestComplete object model, you need to register it in the TestComplete extensibility manager (see Creating Scripting Objects From Application Objects). In Delphi Connected Applications, you can obtain this manager using the Manager
function (it is defined in TCConnect.pas).
To register a custom scripting object, use the manager’s AddName
method. The method call can be inserted in the application’s initialization routine, or in a routine that is called upon a specific event. In our example, we will add a button control to the application form and place the registration code in the button’s OnClick
event handler. This way, we will be able to easily re-register our object in subsequent TestComplete sessions while the application is running.
The sample code is provided below. It requires a form that has the class name TForm1 and contains a button named Button1.
Delphi
{Main.pas}
unit Main;
interface
uses
Windows, SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls,
TCConnect, RuntimeObjectUnit, ComObj, ActiveX;
type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
FRuntimeObject: TSampleRuntimeObject;
FRegistered : bool;
const FRuntimeObjectName : WideString = 'SampleRuntimeObject';
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FRuntimeObject := TSampleRuntimeObject.Create;
FRegistered := False;
end;
procedure TForm1.Button1Click(Sender: TObject);
const
ProjectPath = 'TCProject\SampleRuntimeObject.pjs';
begin
try
// Open a project suite in TestComplete
TC.Visible := True;
TC.Integration.OpenProjectSuite(aqFileSystem.ExpandFileName(ProjectPath));
// Register FRuntime object as a scripting object
Manager.AddName(FRuntimeObjectName, False, FRuntimeObject as IDispatch);
FRegistered := True;
except
on E: Exception do ShowMessage('Count not register ' + FRuntimeObjectName + ':'#13#10 + E.Message);
end;
end;
end.
To unregister an object, use the RemoveName
method of the TestComplete extensibility manager. In our example, we will place the unregistration code in the form’s Close
event handler, so that the object is unregistered when the user exits the application by closing the form. Since the unregistration makes sense only if the object has been previously registered and if TestComplete is running, we check both these conditions before calling the RemoveName
method:
Delphi
{Main.pas}
type
TForm1 = class(TForm)
...
procedure FormDestroy(Sender: TObject);
...
end;
procedure TForm1.FormDestroy(Sender: TObject);
const TCClassName = 'TestComplete.TestCompleteApplication.12';
begin
if FRegistered and (GetActiveOleObject(TCClassName) <> nil) then
Manager.RemoveName(FRuntimeObjectName);
end;
Finally, you can re-compile your application.
Working With Custom Scripting Object
After a custom scripting object is registered in TestComplete, it is displayed in the Code Completion window and can be used in scripts:
You can get and set the object’s property values, call its methods and check their return values the same way you would with standard scripting objects such as TestedApps
, Log
and others. The only difference is that the processing is performed by your application rather than by TestComplete.
The code snippet below demonstrates how you can work with the sample scripting object we have created earlier in this topic. This object is available in TestComplete from the time you launch the application and click the button on its main form and until the application is closed. Note that, despite the object is a part of a Delphi application, it can be used in scripts written in any scripting language, not only DelphiScript:
JavaScript, JScript
function Main()
{
SampleRuntimeObject.Text = "Hello, world!";
SampleRuntimeObject.ShowText();
}
Python
def Main():
SampleRuntimeObject.Text = "Hello, world!"
SampleRuntimeObject.ShowText()
VBScript
Sub Main
SampleRuntimeObject.Text = "Hello, world!"
SampleRuntimeObject.ShowText
End Sub
DelphiScript
procedure Main;
begin
SampleRuntimeObject.Text := 'Hello, world!';
SampleRuntimeObject.ShowText;
end;
C++Script, C#Script
function Main()
{
SampleRuntimeObject["Text"] = "Hello, world!";
SampleRuntimeObject["ShowText"]();
}
See Also
Creating Scripting Objects From Application Objects
Connected Applications - Overview
Creating Connected Applications in Delphi