Creating Self-Testing Applications in C++

Applies to TestComplete 15.0, last modified on November 17, 2021
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 topic describes how to create Self-Testing Applications with 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 Self-Testing Applications in managed Visual C++.

Creation of a C++ Self-Testing Application includes three steps:

  1. Preparing your C++ project
  2. Writing test code in your C++ Self-Testing Application
  3. (Optional) Writing code in your TestComplete project

The description of each step is below. As you will see, the creation of a Self-Testing Application is very similar to creating a Connected Application. The key difference is that the Self-Testing Application should run test code in a separate thread (see 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:

      • Right-click 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++ Self-Testing Applications

  • 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"

    For more information on the Script.h file, its classes and functions, see Creating Connected Applications in C++.

  • 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.)

  • Now, initialize the COM libraries by inserting a call to the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA macro in the main thread of your application. For instance:

    C++

    ...
    using namespace TestComplete;
    IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA
    ...

    This macro is declared in the script.h file. It will initialize COM libraries and create global variables that provide access to TestComplete internal objects: Log, Sys, Regions, etc.

    In order to use this macro in Visual C++, you should either define the _WIN32_DCOM constant or define the _WIN32_WINNT constant to be greater than or equal to 0x0400.

    You only have to use this macro once in the main thread of your code. If your application calls this macro twice, an error will occur.

    IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA initializes COM for the multi-threaded object concurrently (using the COINIT_MULTITHREADED value). If you have already initialized COM in your application for an apartment-threaded object concurrently (COINIT_APARTMENTTHREADED), you should use a similar macro - IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS. Otherwise, using the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA macro will cause an error. Also, if you have already initialized COM for a multi-threaded object concurrently, a call to IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS will cause an error. It is recommended to use a multi-threaded model (the xxxx_MTA macro).

    If you use the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS macro (not xxxx_MTA), or if you do not use any of the macros at all, you should initialize COM yourself (see step 8).

  • Create a separate thread for the procedure to run in, unless it does not call for onscreen inputs (e.g. button clicks, menu selections, etc.) serviced by the current thread.

    If you have not yet initialized COM using the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA macro in the main thread, you should initialize it now by using one of the following ways:

    • Place a call to the CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) function at the beginning of your thread, and a call to CoUninitialize() at the end of your thread.

    • Declare a variable of the COleInit type. The class COleInit is declared in script.h. Its constructor calls the CoInitializeEx function, and the destructor calls CoUninitialize. The variable will be destroyed (the destructor will be called) when the thread finishes and COM will be uninitialized when testing is over.

    Note that the IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS or IMPLEMENT_TESTCOMPLETE_GLOBAL_OBJECTS_MTA macros initialize both COM libraries and global variables used to access TestComplete internal objects. If you do not use these macros, you may need to update your scripts.

  • Copy one or more test routines from TestComplete C++ scripts to your application source. Of note, normally test routines use the p and w variables. When imported to a C++ application, they become variables of the var type. The COleInit variable, which is used to initialize COM, should be declared before any var variables, otherwise, an error will occur. If you do not use the COleInit variable, you should assign NULL to all var variables before COM is uninitialized. For example:

    C++

    var p, w;
    ...
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    ...
    p = NULL; // <-- Correct
    CoUninitialize();
    w = NULL; // <-- Incorrect!!!
    // This should be done before CoUninitialize

    ...

  • 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)

    For more information on writing test code, see Creating Connected Applications in C++.

  • In order for the test code located in a Self-Testing Application to run successfully, TestComplete must be in the script-running mode. To run the test code, you should either launch the Self-Testing 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 Self-Testing 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 Self-Testing 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.

Writing Code in TestComplete Projects

In order for Self-Testing 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 Self-Testing Application from TestComplete. To do this:

  • Open your project in TestComplete.

  • Add your Self-Testing 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 Self-Testing Application and wait while it performs the testing actions. For instance:

    JavaScript, JScript

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

    Python

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

    VBScript

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

    DelphiScript

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

    C++Script, C#Script

    function Test()
    {
      var p;
      // Launches the Self-Testing Application and obtains the process
      // that corresponds to your Self-Testing Application
      p = TestedApps["Items"](0)["Run"]();
      // Delays script execution while 
      // the Self-Testing 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 Self-Testing Application is closed. In order to stop the script run from the Self-Testing 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

Self-Testing Applications
Running Connected and Self-Testing Applications
Connected Applications - Overview
Creating Connected Applications in C++

Highlight search results