TestComplete samples (both built-in and additional) are located in the <Users>\Public\Public Documents\TestComplete 15 Samples folder.
Some file managers display the Public Documents folder as Documents.
Information in this topic applies to desktop applications only. |
In TestComplete, you can call routines that reside in any .NET assembly, from your scripts. The assembly can be supplied with the .NET Framework or a third-party .NET application.
Calling .NET routines via dotNET Object
Calling .NET Routines via Application Domain
Calling .NET Routines With Optional Parameters
Requirements
-
A license for the TestComplete Desktop module.
-
The .NET Classes Support feature enabled in TestComplete.
If you experience issues with accessing .NET classes, select File > Install Extensions from the TestComplete main menu and check whether the .NET Classes Support feature is enabled.
Calling functions from .NET assemblies is not supported for .NET Core and .NET 5.0 - 7.0 applications. |
Calling .NET routines via dotNET Object
You can use a special dotNET
object to access .NET assemblies, types and type members.
Configuring Project’s CLR Bridge Settings
To call routines from a .NET assembly via the dotNET
object:
-
Make the assembly available to the script engine.
Add the needed assembly to the project’s CLR Bridge list. This list contains .NET assemblies whose functions will be available to your scripts through the
dotNET
object:-
Select Tools > Current Project Properties from the TestComplete main menu.
-
Select the CLR Bridge category.
-
To add one or more assembles from the global assembly cache (GAC), click Browse GAC and select the needed assemblies.
To add one or more assemblies from the disk, click Browse Files and select the needed files.
Notes:
-
TestComplete always has access to the mscorlib.dll assembly (even though it is not in the CLR Bridge list). You can always use mscorlib.dll’s classes in your tests.
-
After you remove an assembly from the list, click Reload to unlock the assembly’s file. Otherwise, TestComplete will keep the assembly locked for read-write access until you exit TestComplete.
-
-
Specify the type of hosting process.
TestComplete loads .NET assemblies into a helper hosting process, tcHostingProcess.exe. TestComplete can work with both 32- and 64-bit assemblies, and the bitness of the hosting process must match the bitness of the assembly. Otherwise, TestComplete will not be able to load the assembly to the hosting process.
The Preferred architecture of the assembly hosting process setting defines the bitness of the hosting process. The possible values are:
-
32-bit
-
64-bit
-
The same as the operating system
Notes:
-
TestComplete can create a 64-bit hosting process and load 64-bit assemblies in it only in 64-bit operating systems.
-
32-bit assemblies can only be loaded in the 32-bit hosting process, and 64-bit assemblies can be only loaded in the 64-bit hosting process. Therefore, if the assemblies list contains both 32- and 64-bit assemblies, TestComplete will not load assemblies whose bitness does not match the bitness of the hosting process.
-
When you opened two projects and one of them uses the 32-bit hosting process while another uses the 64-bit hosting process, TestComplete will create two instances of the hosting process: one for 32-bit assemblies and another one for 64-bit assemblies.
-
TestComplete shares hosting processes among projects. It does not create a separate process for each test project. That is, all the projects with the same CRL Bridge bitness will use the same hosting process instance.
-
-
Specify the calling thread type.
To specify the apartment model of the calling thread, use the Preferred apartment model of the calling thread setting that belongs to the CLR Bridge group of project properties. The possible values are:
-
Single-threaded apartment
-
Multi-threaded apartment
-
Does not matter
-
Calling Routines From .NET Assemblies
Assemblies added to the CLR Bridge options become available in scripts as child objects of the dotNET
object. Types defined in a specific assembly are, in their turn, child objects of the assembly node. The object corresponding to a type provides access to subtypes, static members and constructors defined in this type.
The Code Completion window shows all the available assemblies, types and type members:
To call static members of a .NET class:
dotNET.namespace.class.subclass.method(parameters)
dotNET.namespace.class.subclass.property(parameters)
TestComplete automatically converts simple data types (such as strings, integers and Booleans) you pass as parameters to .NET-compatible values.
You can pass parameters of the Object type to the CLR Bridge engine only if they are descendants of the |
Separate the namespace and class name (and subclass name) using dots. Replace the dots used in the namespace name with an underscore character.
To call non-static members:
First create an instance of the needed class by calling the class constructor or a static member that create a new class instance:
dotNET.namespace.class.zctor()
dotNET.namespace.class.zctor_2(parameters)
Note: | Normally, the class constructor name is _ctor() . A class can have several constructors ( _ctor(), _ctor2(), _ctor3() , etc). However, in VBScript an identifier cannot begin with an underscore ( _ ). Therefore, to keep _ctor methods compatible with VBScript, TestComplete replaces the leading underscore character with the letter z in method names. For example, to call the _ctor3 method, use zctor_3 . |
For more information on creating instances of .NET classes in scripts, see Creating Instances of .NET Classes Defined in Applications.
Calling .NET Routines via Application Domain
All process
objects that correspond to .NET applications have the AppDomain
method. The method provides access to the application domain. The object returned by the AppDomain
method is a wrapper for the .NET AppDomain
object.
TestComplete adds an extra dotNET
property to the underlying .NET AppDomain
object. The property provides access to classes defined in the application and to classes defined in assemblies loaded to the application domain.
Note: | The dotNET property also provides access to all classes declared in the mscorlib.dll assembly. |
To call a class member via AppDomain:
Sys.Process("MyProcessName").AppDomain("AppDomainName").dotNET.namespace.class.subclass.method(parameters)
Sys.Process("MyProcessName").AppDomain("AppDomainName").dotNET.namespace.class.subclass.property(parameters)
To call a non-static member:
First create a class instance using the class constructor or a special static member (see above):
Sys.Process("MyProcessName").AppDomain("AppDomainName").dotNET.namespace.class.zctor_2.(parameters)
For more information on creating instances of .NET classes in scripts, see Creating Instances of .NET Classes Defined in Applications.
The advantage of the AppDomain.dotNET
property over the dotNET
object is that you can create instances of application classes without adding application assemblies to the project’s CLR Bridge list.
If you need to create a .NET object to pass it as a parameter to an application routine, we recommend that you create that object by using the application domain. This way you will be able to avoid compatibility issues if you have several versions of .NET Framework installed on your computer.
You cannot pass non-.NET objects as parameters to .NET application routines. For more information, see Creating Instances of .NET Classes Defined in Applications. |
Calling .NET Routines With Optional Parameters
TestComplete does not allow omitting optional parameters when calling .NET functions from your tests. That is, you must specify all the parameters in the call, including the optional ones.
This means that if you want to use the default parameter values, you have to specify them explicitly in the call. A partial workaround to this is passing dotNET.System.Type.Missing
as optional parameter values. For example, if you have a method declared in the following way —
{
static public class MyTestClass
{
// This method takes two parameters.
// The Param1 parameter is required, the Param2 parameter is optional.
static public void Method1(int param1, string param2 = "")
{
…
}
}
}
— then to call it from TestComplete scripts, you can use the following code:
Script
dotNET.TestNamespace.MyTestClass.Method1(1, dotNET.System.Type.Missing)
Note, however, that this workaround does not work for integer, double and boolean optional parameters. You can use it for string, date, object and other parameter types. As for the integer, boolean or decimal optional parameters, you have to specify appropriate integer, double and boolean values in the call.
Working With Values Returned by .NET Routines
In .NET, all data types are objects. Therefore, there are some specifics of using values returned from .NET routines in your tests:
-
.NET integer, double and boolean values are compatible with TestComplete data types. You can use them in tests directly.
-
Access the values of .NET Decimal and DateTime objects and of enumerable members via the
OleValue
property.For example, to access the
System.DataTime.UtcNow
property holding the current UTC time:JavaScript, JScript
dotNET.System.DateTime.UtcNow.OleValue
Python
dotNET.System.DateTime.UtcNow.OleValue
VBScript
dotNET.System.DateTime.UtcNow.OleValue
DelphiScript
dotNET.System.DateTime.UtcNow.OleValue
C++Script, C#Script
dotNET["System"]["DateTime"]["UtcNow"]["OleValue"]
In some cases, you can use
OleValue
with .NET strings (System.String
objects). For example, you may need to useOleValue
to pass a string value as a parameter to a user-defined script function or to compare the value with another string. -
Single-dimensional .NET arrays have the extra
OleValue
property that returns a Variant-compatible array. This way you can use native array operations and functions of scripting languages with the returned array.For example, in VBScript, you can use the
LBound
andUBound
functions to determine an array’s lower and upper bounds and access array elements using the parenthesis syntax:arr(index)
.In JScript, С#Script and C++Script arrays obtained via the
OleValue
property are not compatible with native array formats. They should be first converted to native arrays by using thetoArray()
method.JavaScript
function newTest()
{
var dotnet_str = dotNET.System.String.Copy("Hello, world!");
var dotnet_array = dotnet_str.ToCharArray();
// Converting to a native array
var array2 = dotnet_array.OleValue;
for(let i = 0; i < array2.length; i++)
Log.Message(array2[i]);
}JScript
function newTest()
{
var dotnet_str = dotNET.System.String.Copy("Hello, world!");
var dotnet_array = dotnet_str.ToCharArray();
// Converting to a native array
var array2 = dotnet_array.OleValue.toArray();
for(var i = 0; i < array2.length; i++)
Log.Message(array2[i]);
}Python
def newTest(): dotnet_str = dotNET.System.String.Copy("Hello, world!") dotnet_array = dotnet_str.ToCharArray() # Converting to a native array array2 = dotnet_array.OleValue for i in range(len(array2)): Log.Message(array2[i])
VBScript
Sub newTest
Dim dotnet_str, dotnet_array, array2, i
Set dotnet_str = dotNET.System.String.Copy("Hello, world!")
Set dotnet_array = dotnet_str.ToCharArray()
' Converting to a native array
array2 = dotnet_array.OleValue
i = 0
For i = LBound(array2) To UBound(array2)
Log.Message(array2(i))
Next
End SubDelphiScript
procedure newTest;
var dotnet_str, dotnet_array, array2, i;
begin
dotnet_str := dotNET.System.String.Copy('Hello, world!');
dotnet_array := dotnet_str.ToCharArray();
// Converting to a native array
array2 := dotnet_array.OleValue;
for i := VarArrayLowBound(array2,1) to VarArrayHighBound(array2,1) do
Log.Message(array2[i]);
end;C++Script, C#Script
function newTest()
{
dotnet_str = dotNET["System"]["String"]["Copy"]("Hello, world!");
dotnet_array = dotnet_str["ToCharArray"]();
// Converting to a native array
array2 = dotnet_array["OleValue"]["toArray"]();
for(var i = 0; i < array2.length; i++)
Log["Message"](array2[i]);
}Alternatively, you can use the
GetValue
method to access .NET array items.JavaScript
function arrayTest()
{
var dotnet_str = dotNET.System.String.Copy("Hello, world!");
var dotnet_array = dotnet_str.ToCharArray();
for(let i = 0; i < dotnet_array.Length; i++)
{
var elem = dotnet_array.GetValue(i);
Log.Message(elem);
}
}JScript
function arrayTest()
{
var dotnet_str = dotNET.System.String.Copy("Hello, world!");
var dotnet_array = dotnet_str.ToCharArray();
for(var i = 0; i < dotnet_array.Length; i++)
{
var elem = dotnet_array.GetValue(i);
Log.Message(elem);
}
}Python
def arrayTest(): dotnet_str = dotNET.System.String.Copy("Hello, world!") dotnet_array = dotnet_str.ToCharArray() for i in range(dotnet_array.Length): Log.Message(dotnet_array.GetValue(i))
VBScript
Sub arrayTest
Dim dotnet_str, dotnet_array, array2, i, elem
Set dotnet_str = dotNET.System.String.Copy("Hello, world!")
Set dotnet_array = dotnet_str.ToCharArray()
For i = dotnet_array.GetLowerBound(0) To dotnet_array.GetUpperBound(0)
Log.Message(dotnet_array.GetValue(i))
Next
End SubDelphiScript
procedure arrayTest;
var dotnet_str, dotnet_array, array2, i, elem;
begin
dotnet_str := dotNET.System.String.Copy('Hello, world!');
dotnet_array := dotnet_str.ToCharArray();
for i := dotnet_array.GetLowerBound(0) to dotnet_array.GetUpperBound(0) do
Log.Message(dotnet_array.GetValue(i));
end;C++Script, C#Script
function arrayTest()
{
dotnet_str = dotNET["System"]["String"]["Copy"]("Hello, world!");
dotnet_array = dotnet_str["ToCharArray"]();
for(var i = 0; i < dotnet_array.Length; i++)
{
var elem = dotnet_array["GetValue"](i);
Log["Message"](elem);
}
} -
Two- and multidimensional .NET arrays do not have the
OleValue
property. To get the array elements, use its nativeGet(index1, index2, ..., indexN)
method. -
To work with other objects, use their internal properties and methods.
Samples
The following example shows how you can create a System.String
object (defined in the mscorlib assembly) and call methods of this object in scripts:
JavaScript, JScript
function Test()
{
var str, i;
// Calling a class instance constructor
str = dotNET.System.String.zctor_8(0x41, 3);
Log.Message(str.OleValue); // Using the OleValue property
// Calling a static method
str = dotNET.System.String.Copy("Hello, world!");
// Calling a class instance (non-static) method
i = str.IndexOf("w");
Log.Message(i);
}
Python
def Test():
# Calling a class instance constructor
str = dotNET.System.String.zctor_8(0x41, 3)
Log.Message(str.OleValue) # Using the OleValue property
# Calling a static method
str = dotNET.System.String.Copy("Hello, world!")
# Calling a class instance (non-static) method
i = str.IndexOf("w")
Log.Message(i)
VBScript
Sub Test
Dim str, i
' Calling a class instance constructor
Set str = dotNET.System.String.zctor_8(&H41, 3)
Log.Message str.OleValue ' Using the OleValue property
' Calling a static method
Set str = dotNET.System.String.Copy("Hello, world!")
' Calling a class instance (non-static) method
i = str.IndexOf("w")
Log.Message i
End Sub
DelphiScript
procedure Test;
var str, i;
begin
// Calling a class instance constructor
str := dotNET.System.String.zctor_8($41, 3);
Log.Message(str.OleValue); // Using the OleValue property
// Calling a static method
str := dotNET.System.String.Copy('Hello, world!');
// Calling a class instance (non-static) method
i := str.IndexOf('w');
Log.Message(i);
end;
C++Script, C#Script
function Test()
{
var str, i;
// Calling a class instance constructor
str = dotNET["System"]["String"]["zctor_8"](0x41, 3);
Log["Message"](str["OleValue"]); // Using the OleValue property
// Calling a static method
str = dotNET["System"]["String"]["Copy"]("Hello, world!");
// Calling a class instance (non-static) method
i = str["IndexOf"]("w");
Log["Message"](i);
}
TestComplete also includes a sample project that shows how to call functions from .NET assemblies via the dotNET
object:
Applications:
<TestComplete Samples>\Desktop\Using .NET Classes\Application\UserApp
<TestComplete Samples>\Desktop\Using .NET Classes\Application\UserClassLib
TestComplete project suites:
<TestComplete Samples>\Desktop\Using .NET Classes
Note: | If you do not have the sample, download the TestComplete Samples installation package from the support.smartbear.com/testcomplete/downloads/samples page of our website and run it. |
See Also
Using External Functions
About Testing .NET Applications
Accessing Native Properties and Methods of .NET Objects
Calling DLL Functions From Tests
Project Properties - CLR Bridge Options
TestComplete Helper Objects