Programming with the TestStand API

Overview

This document introduces the use of the NI TestStand API, which contributes to the power and flexibility of TestStand. The TestStand API provides an object-oriented interface to all TestStand capabilities. For most basic applications there is no need to interact directly with the object model, but when you understand the internal workings of TestStand, you gain a vision of what you can accomplish to quickly create advanced TestStand solutions.

Contents

TestStand Architecture and the TestStand API


A well designed, modular testing architecture provides immense value. You can reuse a generalized, adaptable architecture on a range of test systems to extend the lifetime of the test system and to reduce test development costs. TestStand provides a platform built on modularity to simplify the development of test systems and corresponding tests. The power of TestStand lies in its open architecture, which you can use to create complex and flexible test solutions.

The TestStand Engine provides the functionality for TestStand Components, which communicate with the engine through the TestStand API


TestStand has a clear separation between the presentation layer (what the user sees) and the business logic layer (the actions behind a user action). These layers communicate using the TestStand API. This approach enables you to extend TestStand by building additional components which use the TestStand Engine via the TestStand API, such as creating custom user interfaces, dynamically controlling the flow of tests, creating sequences on the fly, and developing other advanced solutions.

TestStand API Architecture

The TestStand Engine is an ActiveX/COM automation server that exposes functionality through an API. Microsoft developed the ActiveX application communication standard to provide a method of communication between applications. Widely used in the industry for many years, ActiveX is built on COM technologies. Because TestStand is built on COM, it will continue to work on future versions of Windows operating systems beyond the lifespan of ActiveX.

ActiveX uses a client/server approach. An ActiveX server is an application that exposes specific functionality to clients that follow the ActiveX standard. In addition, ActiveX applications use Object Oriented Programming (OOP).

The ActiveX server architecture allows any programming language capable of invoking ActiveX code, such as LabVIEW, LabWindows™/CVI™, C#, VB .NET, or C++, to interact with the TestStand Engine. When programming with the TestStand API, the implementation depends on the language you use. For example:

  • LabVIEW uses Property and Invoke Nodes to make API calls.
  • LabWindows/CVI uses an instrument driver wrapper around API calls.
  • C# or VB .NET call the API using an interop assembly TestStand provides.
  • TestStand itself provides an ActiveX/COM Adapter to access the API, and you can also use expressions to access the API directly.

Regardless of the way you access the API, the resulting behavior is the same in any environment, since the functionality is implemented within the TestStand engine regardless of the interface you use.

API Classes

The TestStand API defines several classes to represent types of TestStand objects, such as the SequenceFile class or the Execution class. Each of these classes defines properties and methods to access relevant data or perform actions. For example, the SequenceFile class defines the Path property to store the path of the sequence file on disk, and the Save method to save the sequence file.

Refer to the TestStand API reference help topic for a full list of the available classes defined in the TestStand API. Click a particular class to see more information on it, and the properties and methods it defines. 

 

Class Inheritance

Many classes in TestStand are related through inheritance: where a more specific class can inherit properties or methods from a more generic class. For example, the SequenceFile class is a more specific version of the PropertyObject class. The TestStand API defines an inheritance relationship between these classes to allow objects of a more specific class to have access to the properties and methods of more generic classes.

The SequenceFile class inherits properties and methods from the more generic PropertyObjectFile and PropertyObject classes

 

Almost all TestStand API classes inherit from the base PropertyObject class, which includes common methods and properties that TestStand objects share. The PropertyObject class defines generic properties, such as Name and Numeric Format, and provides common methods for object management, such as cloning, setting and getting values, creating and deleting objects, or manipulating arrays. Because most TestStand API classes inherit from the PropertyObject class, they can also access these generic properties and methods. For example, you can use the PropertyObject.Clone() method to create a copy of a step, a sequence, or a sequence file object.

Many development environments prevent you from accessing the properties of a parent class directly. Similarly, in TestStand you cannot call the Clone() method directly on a SequenceFile object. However, the TestStand API provides methods to cast an object to access properties and methods of the more generic class. To access properties and methods defined in the PropertyObject class, you can cast the object into its parent class by calling the AsPropertyObject method. For example, to access the Clone() method on a sequence file object, use
SequenceFile.AsPropertyObject.Clone().

Refer to the NI TestStand Help for more information about the API inheritance and the PropertyObject class properties and methods.


Dynamic Properties versus Built-In Properties

TestStand Objects have two distinct types of properties:

  • Built in properties (API Properties), which are defined by the class of the object, are present for all objects of a certain class.
  • Dynamic Properties (Sub-Properties), which are defined by the object, can differ between objects of the same class.

A step object has Dynamic Properties that can differ based on the step type, and Static properties which are defined by the Step class in the TestStand API


It can be easy to confuse these two distinct types of properties, since you can access both in a TestStand expression using the “.” Operator. However, when you use the API in other programming languages, only built-in properties are available through direct access, such as when using a property node in LabVIEW.


To access Dynamic Properties, you use the PropertyObject API methods, such as GetValString() and GetValNumber(), using a LookupString to specify the name of the Dynamic Property:



In some cases, you can access a property in multiple ways using either dynamic properties or Built-in properties. When using the TestStand API in a code module, using built-in properties is preferable, since these properties can be accessed directly without the need for maintaining lookup strings. 

 

TestStand Object Relationships

TestStand Objects can contain other objects of a different class, referred to as API Containment . For example, a SequenceFile object contains Sequence objects for the sequences defined in the sequence file. Sequence objects, in turn, each contain Step objects.

Objects in the TestStand API often contain other objects of a different class

Understanding the containment relationships between objects is helpful when navigating specific objects. If a parent object contains multiple child objects of a certain class, you must provide either a property name or index to specify the desired child object. For most child objects, you access the contained objects from a parent object using a specific getter method, which accepts the object name or index as a parameter. For example, to access a step within a sequence file, you use:

SequenceFile.getSequenceByName(“MainSequence”).GetStepByName(“RAM Test”, StepGroup_Main)

In addition, child objects can access their parents through the API. Since a child object always can have only one parent, you use a property rather than a getter method to directly access the parent. For example, if you have a SequenceContext object and need to access the parent execution, you could use:

ThisContext.Thread.Execution

In many cases, built-in properties are provided to access more distant ancestors. For example, you can directly access the execution object from a Sequence Context object:

ThisContext.Execution

 

Navigating through TestStand API Objects

In addition to navigating using containment relationships, many classes provide properties or methods to access other related objects. For example, the Module class provides the Adapter property to access the corresponding adapter which is executing. 

You can use the chart provided in the TestStand API Reference help topic to determine how you can access a desired object from the current object. A subset of this chart is shown below.
 

From the sequenceContext object, you can navigate object relationships to access other objects

Accessing the TestStand API

There are typically two approaches you can use to access the API, depending on the type of application you are creating:

  • For standalone applications, you must create a new instance of the TestStand Engine.
  • For code modules or other tools called from an existing application, you must pass in an existing reference to the TestStand Engine.

 

Creating a Standalone TestStand Application

To use the TestStand API in a new application, you must first create an instance of the TestStand engine. Any TestStand application or process, such as a TestStand user interface, Sequence Editor, or custom utility, maintains a single instance of the engine, or singleton, to perform any TestStand functions. The engine maintains references to all in-memory objects, sets up and controls executions, and stores the context data for a TestStand session as well as station globals and user information.

The TestStand Engine provides methods you use to create other TestStand objects, which are denoted with the “new” keyword, such as the following methods:

  • Engine.NewSequenceFile()
  • Engine.NewStep()
  • Engine.NewExecution()
  • Engine.NewPropertyObject()

For a full list of the properties and methods available from the Engine object, refer to the TestStand Engine topic for more information.

When the application completes, you must shut down the TestStand Engine before exiting the application. A two-step shutdown process is required to ensure that the user is given a chance to terminate any running executions, as explained in the Shutting Down the Engine topic in the TestStand help.

NI recommends using the TestStand UI controls to develop TestStand Applications and User Interfaces rather than directly creating a TestStand engine object to reduce the complexity of your program. The TestStand UI controls provide an abstraction layer above the TestStand API which makes it easier to develop stand-alone TestStand applications. Refer to the UI controls API section of this document for more information on using the UI Controls.


Calling a Code Module or Tool from an Existing Application

When using the API in a code module or tool you call from another TestStand application, you use the TestStand engine created by the top-level application. If the code is called from an executing sequence, such as a code module, this is best accomplished using an input parameter for the SequenceContext. This is preferable to directly passing the TestStand engine because the sequence context provides access to the current state of the execution in addition to the TestStand engine object.

The SequenceContext represents the current execution state of a sequence, providing access to a snapshot of all the data for a particular executing sequence. Each executing sequence in any thread has its own SequenceContext.

When browsing the Variables view, the list you see are the Sequence Context First-Level Properties, which includes all variable types, the current step, and the RunState property. The SequenceContext also provides references to many other objects as built-in properties.

 

RunState Versus SequenceContext


The RunState Property and the SequenceContext both provide access to many of the same objects, such as the current execution, thread, sequence file, and sequence. However, the RunState Property contains these objects as dynamic properties, unlike SequenceContext which exposes them as built-in properties.

For this reason, use the RunState property when accessing information about the state in TestStand expressions, while the SequenceContext is more appropriate for code modules, where you cannot directly access dynamic properties.


 The SequenceContext provides execution state information through built-in and dynamic properties, while the RunState property provides state information through only dynamic properties.

Persistence of Sequence Data

Before executing the steps in a sequence, TestStand creates a run-time copy of the sequence to maintain separate local variable and step property values for each sequence invocation. In most cases, when you access objects from the Runstate or SequenceContext within an executing sequence, the objects are these run-time copies. This means that any changes you make to these objects will not persist after the execution completes, for example changing the values of local variables or programmatically creating a Sub-Property of a Parameter, will not affect the sequence file on disk:

Locals.SetValString("RuntimeVariable",1, "value")

Objects that inherit from the PropertyObjectFile class, such as SequenceFile objects, do not have a separate run-time copy, so changes you make through these objects will persist after the execution completes. For example, accessing the Locals property through the SequenceFile object allows you to create a persistent local variable.

RunState.sequencefile.GetSequenceByName("MainSequence").Locals.SetValString("PersistantVariable",1, "value")

Common Applications of the TestStand API

While the TestStand API provides the ability to automate all TestStand functionality, there are a few more common applications of the API:

  • Creating Custom Properties
  • Creating New Sequence Files
  • Modifying existing sequences

 

Creating Custom Properties

You can use the TestStand API to dynamically generate custom properties at runtime, for example, to add specific diagnostic data to the test results if the test fails for a particular component or add custom data to the report header. 

There are many ways to create custom properties through the API. For primitive data types, using the “SetVal” methods with the InsertIfMissing option provides the simplest method for creating new properties. For example, you can use the following expression to add a new property to a numeric limit test step:

RunState.Sequence.Main["Numeric Limit Test"].AsPropertyObject.SetValString(
"Result.extraResult",
PropOption_InsertIfMissing,
"this string is an extra result")

To add a custom property to the report, you must also set the IncludeInReport flag for the object, which the Report generator uses to choose which result properties to log:

RunState.Sequence.Main["Numeric Limit Test"].AsPropertyObject.SetFlags(
"Result.extraResult",
0,
PropFlags_IncludeInReport)

For more details on using the API to add data to the test report, refer to the Adding Custom Data to a Report example.

For more complex properties such as containers, you will need to create the properties directly using the NewSubProperty() method, which allows you to create containers, instances of data types, and arrays. For example, to create a new local variable of the Error type, you would use the expression:

Locals.NewSubProperty("ComplexContainer.Error",PropValType_NamedType, False, "Error",0)

For more details on using the API to create properties, refer to the [Creating new properties using API] example.

 

Creating New Sequences

To automate the process of creating a sequence file based on user input, you can use the TestStand API to generate new sequence files or create modified copies of an existing file. For example, you may want to create a tool which generates a starting point sequence file based on certain user input or performs specific modifications to steps in an existing sequence file.

For more information on creating new sequence files using the API, refer to the Building a Sequence Using the API example.

You can also use the TestStand API to develop a Sequence File Translator to generate sequence files using a custom file format. When creating a sequence file translator, you use the TestStand API to generate sequence files, sequences, steps, and properties based on the data in a file you specify. The Translator framework allows you to integrate this code with TestStand, and directly open files in a custom format. 

For more information on using sequence file translators, refer to the Sequence File Translators topic in the TestStand help


Modifying Sequences

You can use the TestStand API in custom tools you use to perform modifications to existing sequence files. For example, you may want to create a tool which checks for code modules that are specified by an absolute path and replace them with relative paths. 

Refer to the Creating a Sequence File Iteration Tool example for more information.

Additional TestStand APIs

In addition to the Core TestStand API, TestStand provides other APIs which extend the functionality and provide additional features:

  • UI Controls API
  • Adapter API
  • Synchronization Server API

Unlike the Core TestStand API, these APIs are not directly accessible through expressions; you use them through an ActiveX step or a separate code module.


UI Controls API

TestStand includes a set of user interface controls which allow you to quickly develop TestStand User Interfaces. These controls include visible controls for displaying TestStand data, such as the Steps View or Variables View, as well as Invisible Manager controls, which handle much of the communication with the TestStand Engine API in a TestStand User Interface.

When developing a standalone TestStand application, NI recommends that you use the UI controls to develop the application versus creating an instance of the TestStand engine directly.

The UI Controls API allows you to implement common user interface tasks through the manager controls, such as opening and executing sequence files, responding to UI messages, and handling application shutdown. The UI Controls API also provides connection methods used to configure the UI Controls. 

For more information on using the User Interface controls and the UI Controls API, refer to the following help topics:


You can think of the TestStand UI Controls as a layer of software on top of the TestStand Engine API. These controls encapsulate many of the features you need in a user interface, such as opening sequences, running tests, displaying test progress, and so on. The TestStand UI Controls are feature rich and include their own API. Although covering the functionality of the user interface controls is outside the scope of this document, it is important to mention that these controls provide functionality based on top of the TestStand Engine API.

 

Adapter API

The adapter API provides specific classes for the different adapters included in TestStand. Typically, you use the adapter API for adapter-specific information or functionality when using the adapter or module classes in the core API. In this case, you type cast the object to the appropriate adapter API class. For example, you can use the LabVIEWModule class to access LabVIEW-specific properties and methods for the module object in a LabVIEW step.

Use the adapter API to access adapter specific properties and methods for the Module or Adapter classes

 

Refer to the TestStand Adapter API reference for a list of classes provided in the adapter API

 

Synchronization Server API

The Synchronization server API provides direct access to TestStand synchronization objects, such as queues, locks, or notifications. To use this API, you first obtain a reference to the Synchronization manager using the Engine.GetSyncManager method. After casting this object to the Synchronization manager class defined in the synchronization server API, you can use it to access or create new synchronization objects.


Use the SyncManager and  the Synchronization Server API to create and access TestStand synchronization objects in code

 

This API is useful when developing applications that run alongside a TestStand test and need to access information about the state of the execution, such as a status monitor application.

For more information about the classes available, refer to the Synchronization Server API Reference topic.

Was this information helpful?

Yes

No