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
Viewpoint News, March 2009
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.
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?
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:
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:
Step 1 – Build a LabVIEW object that will interface to our hardware
Step 1a – Create init.vi
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
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
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
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
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.
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.’
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
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.