Related Content

Contact Information

Viewpoint Systems, Inc.
800 West Metro Park
Rochester, NY 14623
Phone: 585.475.9555
Fax: 585.475.9645

Viewpoint Data Management, LLC.
800 West Metro Park
Rochester, NY 14623
Phone: 585.475.9555
Fax: 585.475.9645

round top

bulletViewpoint News, March 2009


Mock Objects in LabVIEW

by Benjamin Hysell - bhysell@viewpointusa.com

In Part 4 of our series on Test Driven Development (TDD) in LabVIEW we are going to turn our attention to external resource simulation, or mocking.

When a LabVIEW project grows beyond the scope of a couple of simple VIs where one developer proclaims ‘I can write that application in five minutes,’ to a full-fledged testing system, the application will likely require external resources. DAQ hardware, image acquisition hardware, motion control hardware, and databases all represent different forms of external dependencies; dependencies we will need to interact with in one form or another.

This list is by no means exhaustive; there are literally thousands of external pieces of hardware and software our applications may need to interface with to successfully operate.

While developing applications that interact with external resources we normally need to be directly connected to the hardware/software, however what if we are resource constrained? What if the hardware we need to interface with is unavailable, or operating a 24/7 machine that we can only obtain access to from 11pm - 1am every other Thursday? We have a couple of options.

  • We can work around the access limitations of the hardware/software during development.
  • We can simulate the hardware/software resource in code.

This article will focus on the latter. We are going to simulate external resources, or in the software engineering world, use mock objects. See the Wikipedia article for a full perspective on mock objects and how they are typically used in the text-based world of programming.

Why do we want to mock out our hardware/software?

  • Unit testing algorithms with mock objects allows us to obtain constant, repeatable values from the mocked hardware every time we run the unit test.
  • Obtaining access to the external hardware/software may prove difficult, i.e. we may need to interface to a motion controls system that is off site and is running production product. In this situation it is unlikely we would be able to develop or debug our application while the machine is running.
  • We may only have access to one set of hardware for a team of multiple people…we all can’t be on the hardware at the same time and make any progress.

I’ll take it since you are still reading you are either A) on board and all about mocking or B) interested and want to learn a little more. Let’s get started and mock out some hardware!

If you care to follow along in this article you will need the following hardware/software:

  • LabVIEW 8.6
  • VI Tester by JKI Software
  • An external hardware dependency that does an analog read. I’m using an NI PCI-6281 for my external hardware dependency

Goal: To test my application’s internal logic. To do this I’m going to build a unit test, to test one VI doing data acquisition. My simple application consists of doing four back-to-back analog reads and adding the resulting values together.


Steps for this project:

  • Build the LabVIEW objects that will interface to our hardware
  • Build my application and its logic to perform my calculation
  • Build the mock object
  • Build a unit test

Step 1 – Build a LabVIEW object that will interface to our hardware

  • Start with a blank project and add a class and call it ‘Hardware’
  • Double click on the ‘Hardware.ctrl’ and add a ‘DAQ Task’ as a private member to the ‘Hardware’ class
  • Right click on the ‘Hardware’ class and edit the icon to place the word ‘Hardware’ in the upper portion of the icon
  • Add three method VIs to the object, right click on the class in the project explorer and select ‘New / VI from Dynamic Dispatch Template’
  • Create the VIs ‘init’, ‘dispose’, and ‘read AI’

Step 1a – Create init.vi

  • Lay down a ‘DAQmx Create Channel’ and select ‘AI Voltage’
  • Create controls on the front panel for ‘Physical Channel’, ‘minimum value’, and ‘maximum value’
  • Wire the controls to the connector pane

The finished front panel and block diagram for the init.vi should look like Figures 1 and 2.

Figure 1 Front Panel init.vi


Figure 2 Block Diagram init.vi


Step 1b – Create AI Read.vi

  • Unbundle the object data using an ‘unbundle by name’ control
  • Wire the ‘task out’ into a ‘DAQmx Read’ and select Analog DBL 1Chan 1Samp
  • Wire a ‘10’ into the ‘timeout’ of the ‘DAQmx Read’
  • Wire the data resulting from the ‘DAQmx Read’ to the case structure and create an indicator, wire the indicator to the connector pane

Following along you should have Figures 3 and 4.

Figure 3 Front Panel Read AI



Figure 4 Block Diagram Read AI


Step 1c – Create dispose.vi

  • Place a ‘DAQmx Clear Task’ inside the case structure
  • Use an ‘Unbundle by Name’ and wire the ‘task out’ into the ‘DAQmx Clear Task’

Figures 5 and 6 show the front panel and block diagram for dispose.vi.

Figure 5 Front Panel dispose.vi


Figure 6 Block Diagram dispose.vi


Step 2 – Build the application

  • Create a new VI in the project, call it ‘Gather Data.vi’
  • Lay down an ‘init.vi’, four ‘read AI.vi’, and a ‘dispose.vi’
  • Take the ‘data’ output from the ‘read Ai.vi’ and wire them all together into a ‘compound arithmetic’ control, select ‘add’ as the function.
  • Create controls for ‘Hardware in’, ‘Physical Channel’, ‘minimum value’, ‘maximum value’, ‘error in’, ‘error out’, and ‘result’. Connect all the controls to the connector pane.

Figures 7 and 8 show the resulting front panel and block diagram for Gather Data.vi.

Figure 7 Front Panel Gather Data.vi




Figure 8 Block Diagram Gather Data.vi


At this point we can run our ‘Gather Data’ and should (assuming you’ve connected something up to your DAQ card) perform four different AI reads and add the results together. In my test system I have my AI1 connected to a function generator generating a sine function. Every time I run my ‘Gather Data.vi’ I will receive a different result from the addition function. This is the difficult part of working with hardware and external dependencies; every time I test this VI I am going to receive different results. What I really want to validate is the algorithm (in this case, my add function) contained in this VI. One method to do this is to mock out our hardware and ensure every time we make a call to ‘read AI’ we get the same result. This will allow us to run unit tests against the algorithm ad nausea and always receive the same results.

This will also alert us if something changes in the algorithm during the course of development. If our tests start to fail we know that something happened to the algorithm and not the hardware since we are using mocked hardware to run our unit tests.



Step 3 – Build the Mock Object

  • Add a new class to the LabVIEW project, call it ‘Mock Hardware’
  • Right click on the new class and select ‘Properties’
  • Choose ‘Inheritance’ from the left hand side
  • In the ‘Change Inheritance’ window click on the ‘Hardware.lvclass’ and click the button ‘Inherit From Selected’
  • Click on ‘Ok’ to close out the class properties for ‘Mock Hardware’

We have just added a new object to our project and changed the object inheritance from the root LabVIEW object to the ‘Hardware’ class we defined above.


Step 3a – Add three VIs for override

In our new mock class we are going to override the behaviors of the class we are inheriting from. Since we are going to be working with mock hardware our overridden ‘init’ and ‘dispose’ classes are going to be nothing but pass through VIs that do nothing. The interesting VI is going to be the ‘read AI.vi’ where we are going to simulate the AI reads.

  • Right click on the ‘Mock Hardware’ class and select ‘New \ VI for Override’
  • In the new pop-up window select ‘Hardware.lvclass:Init.vi’
  • Examine the block diagram of the newly created VI and notice how we are calling our parent’s class ‘init’ method
  • Remove the call to the parent’s method and wire all controls to their indicators
  • Repeat the process for the ‘dispose.vi’

For the ‘init.vi’ you will have a very boring block diagram as shown in Figure 9.


Figure 9 Mock Hardware init.vi



Step 3b – Create Mock ‘Read AI.

  • Open up the ‘Read AI’ VI from the ‘Mock Hardware’ class
  • Remove the call to the parent object’s ‘Read AI’
  • Wire all controls to their indicators
  • Create a constant value for the data output of the ‘Read AI’

Every time we make a call with our mock hardware to the ‘Read AI’ we will receive a constant value. There are multiple techniques that we could use to generate consistently different values for each call to ‘Read AI’, these however are out of the scope of this article.


Step 4 - Create our Unit Test

  • In the project explore select ‘Tools / VI Tester / New / Test Case…
  • Name the new test case ‘Hardware Mocking Test’
  • Create a new test VI inside the test class, I’ll call mine ‘test Simple.vi’
  • Open the block diagram for the ‘test Simple.vi’ and create Figure 10

Figure 10 Block Diagram Unit Test


What have we created? We have wired in the object ‘Hardware Mock’ into the ‘Hardware in’ object control of our ‘Gather Data.vi’. Place a break point in the unit test and run the test, turn on ‘execution highlighting’ and see what happens.

Since we wired in the ‘Hardware Mock’ object into our ‘Gather Data.vi’ when we make a call to an overridden VI, LabVIEW will dynamically call the VIs for the ‘Hardware Mock’ class and not the ‘Hardware’ class.

In our full fledged application when we want to run against hardware we would wire in a ‘Hardware’ object into the ‘Gather Data.vi’ and our application would use the VIs of the ‘Hardware’ class which talks to real hardware.


Conclusion

Mocking is a very powerful feature that we can now accomplish in LabVIEW through LabVIEW objects. Although text- based languages still have better tools for full fledged mocking (see Moq from Google, Nmock, and Rhino Mocks), through simple design decisions we too can have the start of a mocking framework.