Creating Connected Applications in C++

Applies to TestComplete 14.30, last modified on November 21, 2019
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.

A Connected Application simulates mouse or keyboard input into itself. Before trying this, please see the Creating Self-Testing Applications in C++ topic. This topic describes how to create a “generic” Connected Application using the following compilers:

  • Visual C++ 7.x (unmanaged code)
  • Visual C++ 2005 (unmanaged code)
  • Visual C++ 2008 (unmanaged code)
  • Borland C++Builder 6.0
  • CodeGear C++Builder 2009
  • Embarcadero C++Builder 2010 and XE
Currently, it is not possible to create Connected Applications in managed Visual C++.

The examples described in this topic are not self-testing as they explain how to “test” MS Paint. Although, you may want to read this topic first before going to the self-testing topic.

Creation of a C++ Connected Application includes three steps:

  • Preparing your C++ project
  • Writing test code in your C++ Connected Application
  • (Optional) Writing code in your TestComplete project

The description of each step is below.

Preparing your C++ project

  • Open an existing project or create a new one in your development tool (C++Builder or Visual C++).

  • If you use Visual C++, disable optimization:

    • In Visual C++ 7.x, 2005 and 2008:

      • Rightlick the project in the Solution Explorer and select Properties from the context menu to display the Project Properties dialog.

      • Switch to the Configuration Properties | C/C++ | Optimization node and select Disabled (/Od) from the Optimization combo box.

      • Click OK to close the dialog.

  • C++Builder users should disable the Code Guard:

    • Select Tools | CodeGuard Configuration from the main menu to display the CodeGuard Configuration dialog.

    • Uncheck the Enable box on the Preferences tabbed page.

    • Click OK to save the changes.
  • Include the following header file in the source file(s) where you want to insert TestComplete C++ script procedures:

    Header file Scripts
    <TestComplete>\Connected Apps\C++\script.h for Microsoft Visual C++ and Borland C++Builder

    For instance,

    C++

    #include "..\..\..\Connected Apps\C++\script.h"
  • Place this directive before the script code in each file where you will add TestComplete scripts:

    C++

    using namespace TestComplete;

    This will resolve a possible conflict of names (Sys, Log, etc.)

Writing Test Code in C++ Connected Applications

  • Add the macro IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS to your code. This macro is declared in the script.h file where it initializes COM libraries and creates global variables that provide access to internal TestComplete objects - Sys, Log, Regions, etc. Note that you should use this macro only once in the main thread of your code. If your application calls this macro twice, an error will occur.

    IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS initializes COM libraries for apartment-threaded object concurrently (using the COINIT_APARTMENTTHREADED value). If you have already initialized your application for multi-threaded object concurrently (COINIT_MULTITHREADED), you should use the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA macro instead of the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS. Otherwise, a call to IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS will cause an error.

    In order to use the MTA macro in Visual C++, you should define either the _WIN32_DCOM constant or the _WIN32_WINNT constant so that it is greater than or equal to 0x0400. Like the non-MTA macro, the MTA macro should be used only once in your code.

  • Write the test code into your C++ source, or copy one or more test functions from TestComplete C++ scripts.

    The script.h file only contains variables for standard TestComplete objects (Sys, Log, Regions, Files and others). If you need to work with objects that are provided by third-party plugins, you should obtain this object in your code by using the GetObjectByName function that is defined in the script.h file:

    C++

    [script.h]
     

    var GetObjectByName(const BSTR ObjName)

    See also note on writing test code below.

  • In order for the test code located in a Connected Application to run successfully, TestComplete must be in the script-running mode. To run the test code, you should either launch the Connected Application from the TestComplete script, or call the RunTest routine (see Running Connected and Self-Testing Applications for more information).

    If you are going to use the RunTest routine, insert a call to it before the first statement of the test code in your Connected Application. To stop the test run initiated with RunTest, use the StopTest routine:

    C++

    RunTest("My Test", "MyProject", "C:\\Work\\MyProjectSuite.pjs");
    ...
    // Test code
    ...
    StopTest();

    If you are going to launch your Connected Application from TestComplete, call the test procedure from your own code. For instance, you can call the test procedure within a button’s OnClick event handler.

  • Compile your application.

Note that the script.h file overloads the "[ ]", "( )" and "=" operators for scripting objects to refer to their properties and methods:

Function Description
TestedApps["RunAll"](); Calls the RunAll method of the TestedApps object.
Sys["Process"]("MSPAINT"); Returns the MSPAINT process.
Log["Message"]("My text"); Posts the My text message to the test log.
Sys["Desktop"]["ActiveWindow"]()["Name"]; Returns the Name property of an active window.
Sys["Child"](0); Returns the first child of the Sys object.

Note that besides TestComplete, script.h allows you to work with other COM servers (e.g. with MS Word) in the same manner. script.h simplifies the syntax used in C++ applications to work with COM servers via late binding. Once you have obtained the IDispatch interface of the desired server, you can address its methods and properties using the C++Script syntax rather than calling the GetIDsOfName, Invoke and other methods. See Writing C++Scripts for more information.

The notation used in TestComplete to refer to object properties and methods via C++ scripts is possible because an object is treated as an associative array, which is a data structure that associates data values with strings. In arrays the index operator ("[]") is used to get access to array elements, in objects it is the property name specified as a string.

To set the value of a property, use the following syntax:

C++, C++Script

// Changes the caption of the active window
Sys["Desktop"]["ActiveWindow"]()["WndCaption"] = (var)"New Caption";

If the property is indexed, you can use any of the following notations:

C++, C++Script

// Property with one index
p["Form1"][Put("PropertyName")](Index) = Value;
// or
p["Form1"][(Put)"PropertyName"](Index) = Value;

C++, C++Script

// Property with two indexes
p["Form1"][Put("PropertyName")](Index1, Index2) = Value;
// or
p["Form1"][(Put)"PropertyName"](Index1, Index2) = Value;

C++, C++Script

// Index can be any OLE compatible value, not just an integer
p["Form1"][Put("PropertyName"), 1, "2nd index"] = Value;
// or
p["Form1"][(Put)"PropertyName"](Index1, "2nd index") = Value;

TestComplete supports properties with up to 10 indexes. If you use more, please contact our support team.

The following code illustrates how to obtain the property value:

C++, C++Script

var v, w;

// Indexed property
v = p["Form1"]["PropertyName"](1, "2nd index");
// Simple, unindexed property
w = p["Form1"]["PropertyName"];

script.h holds a declaration for the var type. It was developed as an alternative to the standard VARIANT type. var makes it easier to work with objects and their properties in C++ scripts. For instance:

C++, C++Script

var w;

w = Sys["ActiveWindow"]();
Log["Message"](w["Name"]);

TestComplete routines work only with OleVariant data types. Values of this type can be converted to any other data type. Conversions are generally automatic, but in some cases the compiler does not have sufficient information about the type to convert it. When this happens, you will get an error message reading: “Ambiguity between 'CVariantWrap::operator A' and 'CVariantWrap::operator B' ”. The solution is to force the conversion to the desired type. For example,

C++, C++Script

if ( w["Exists"] && w["VisibleOnScreen"] ) // Ambiguity error!!!
if (bool(w["Exists"]) && bool(w["VisibleOnScreen"])) // Correct

Writing Code in TestComplete Projects

In order for Connected Application to be able to use TestComplete scripting objects and post messages to the test log, TestComplete must be in the script-running mode. The testing engine switches to this mode when you run a test from TestComplete, or when you call the RunTest routine (see Running Connected and Self-Testing Applications).

If you do not use the RunTest routine, you should launch your Connected Application from TestComplete. To do this:

  • Open your project in TestComplete.

  • Add your Connected Application to the project’s tested applications list. For more information on how to do this, see Defining Applications to Test.

  • Write script code that will launch your Connected Application and wait while it performs the testing actions. For instance:

    JavaScript, JScript

    function Test()
    {
      var p;
      // Launches the Connected Application and obtains the process
      // that corresponds to your Connected Application
      p = TestedApps.Items[0].Run();
      // Delays script execution while 
      // the Connected Application performs the testing actions
      while(p.Exists)
        aqUtils.Delay(500);
    }

    Python

    def Test():
      # Launches the Connected Application and obtains the process
      # that corresponds to your Connected Application
      p = TestedApps.Items[0].Run()
      # Delays script execution while 
      # the Connected Application performs the testing actions
      while(p.Exists):
        aqUtils.Delay(500)

    VBScript

    Sub Test
      ' Launches the Connected Application and obtains the process
      ' that corresponds to your Connected Application
      Set p = TestedApps.Items(0).Run
      ' Delays script execution while
      ' the Connected Application performs the testing actions
      While p.Exists
        aqUtils.Delay 500
      WEnd
    End Sub

    DelphiScript

    procedure Test;
    var
      p : OleVariant;
    begin
      // Launches the Connected Application and obtains the process
      // that corresponds to your Connected Application
      p := TestedApps.Items[0].Run;
      // Delays script execution while
      // the Connected Application performs the testing actions
      while p.Exists do
        aqUtils.Delay(500);
    end;

    C++Script, C#Script

    function Test()
    {
      var p;
      // Launches the Connected Application and obtains the process
      // that corresponds to your Connected Application
      p = TestedApps["Items"](0)["Run"]();
      // Delays script execution while 
      // the Connected Application performs the testing actions
      while (p["Exists"])
        aqUtils["Delay"](500);
    }
  • Make sure this code is called when running the current TestComplete project.

  • As you can see, the script runs until the Connected Application is closed. In order to stop the script run from the Connected Application, use the Runner.Stop method. This method notifies TestComplete that the test run is over and refreshes the Test Log so that it displays the latest test results.

You can now run the test by clicking the button whose OnClick event handler contains the test code.

See Also

Connected Applications - Overview
Creating Event Handlers in Visual C++ Applications
Creating Event Handlers in Delphi and C++Builder Applications
Running Connected and Self-Testing Applications
Self-Testing Applications
Creating Self-Testing Applications in C++

Highlight search results