The idea behind unit testing is elegant and simple, but can be expanded to enable sophisticated series of tests for code validation and regression testing. A unit test is strictly something that ‘exercises’ or runs the code under test. Many developers manually perform unit testing on a regular basis in the course of working on a segment of code. In other words, it can be as simple as ‘I know the code should perform this task when I supply this input; I’ll try it and see what happens.’ If it doesn’t behave as expected, the developer would likely modify the code and repeat this iterative process until it works.
The problem with doing this manually is that it can easily overlook large ranges of values or different combinations of inputs and it offers no insight into how much of the code was actually executed during testing. Additionally, it does not help us with the important task of proving to someone else that it worked and that it worked correctly. The cost and time required is compounded by the reality that one round of testing is rarely enough; besides fixing bugs, any changes that are made to code later in the development process may require additional investment of time and resources to ensure it’s working properly.
Large projects typically augment manual procedures with tools such as the Unit Test Framework to automate and improve this process. Automation mitigates risk of undetected errors, saves costs by detecting problems early, and saves time by keeping developers focused on the task of writing the software, instead of performing the tests themselves.
Creating a Test for a LabVIEW VI
To create a test in LabVIEW using the Unit Test Framework, right click on the VI under test in the Project Explorer and move your cursor over the ‘Unit Tests’ menu item. Select ‘New Test’ to create a new file on disk with an .lvtest extension (see figure 1).
Figure 1: Automatically generate a test for a VI from the menu in the Project Explorer
By default, this file will be saved in the same location as the VI under test; however, .lvtest files can automatically be stored in a pre-determined location, as specified in the Unit Test Framework properties (available from the properties dialog that is available by right-clicking on the .lvproj file in the Project Explorer).
Defining Test Vectors
The next step in creating a test is the definition of a test vector or a test case. VIs, like a function call in text-based programming languages, have inputs and outputs. When a unit test is performed in LabVIEW, a known set of inputs is supplied to the VI. These inputs are paired with a pre-determined set of expected outputs to define a ‘test vector’. The output of the VI after execution is then compared with what was expected (see figure 2) to generate the results. The Unit Test Framework allows the creation of these tests without any modification to code.
Figure 2: Test Vectors (or Test Cases) refer to the pairing of inputs for a unit of code with the expected output. Unit testing compares the expected results with the actual results to generate reports.
Test cases can be specified in a number of different ways using the Unit Test Framework. The most common mechanism is the dialog that appears in LabVIEW if you double click on an .lvtest file in the Project Explorer. In the dialog that appears, select ‘Test Cases’ from the list of categories to specify the inputs and expected outputs. By default, you can specify input values for all controls attached to the connector pane and specify expected output values for any indicators tied to the connector pane (see figure 3).
Figure 3: Setup test cases in the Unit Test Framework dialog by double-clicking a test in the Project Explorer
The comparison that is performed on the output is specific to the data-type.
If you have additional inputs that are not attached to the connector pane, or if you wish to evaluate inputs as outputs, you may configure this from the advanced category under the configuration options (see figure 4). Outputs may also be excluded from comparison by deselecting the checkmark next to the line in the Test Case.
Figure 4: The default behavior only uses controls and indicators on the connector pane for the test case. This can be extended to all controls and indicators by changing the advanced configuration.
As with any programming language, inputs that are unbounded have an infinite number of values. For this reason, inputs are typically selected that represent multiple values from a certain range, but completely exhaustive testing may not be possible.
One .lvtest file can contain multiple test cases. For example, you might create a test that evaluated the VI’s performance when it received incorrect input; however, there are likely numerous combinations of inputs that fall under this category and therefore would be a part of the same test, but each of which would require the definition of a new test case. To add additional test cases, click ‘New’ from the ‘Test Cases’ Category (see figure 5).
Figure 5: One test can contain multiple test cases
In addition to using the ‘Test Cases’ category of this dialog, test vectors can also be specified in an external editor, such as Microsoft Excel, to facilitate programmatic test creation. This feature also enables groups that may not have access to the development environment to define tests.