A study performed in 2008 by the NCBI found that standard advice encouraging flossing for the prevention of cavities and gum disease is not supported by scientific evidence. This conclusion wasn't drawn because scientists discovered that flossing was not a worth while preventative measure, but rather because scientists found that people were doing it incorrectly. Additionally, a study done in 2013 by the ADA reported that 50% of Americans do not floss daily in the first place. When done correctly flossing can help prevent cavities and gum disease; yet 50% of us choose not to do it at all and the majority of the rest end up doing it incorrectly.
If dental experts agree that proper flossing can reduce dental defects, and if proper flossing takes less time than looking at Facebook, then why don't people do it? I can think of many possible reasons:
Luckily for me, my mother-in-law is my dental hygienist. So regardless of my affection for flossing, I do it out of the immeasurable anxiety associated with having my mother-in-law evaluating my dental hygiene twice a year. We don't all have this luxury.
I think a nice parallel can be drawn between flossing as a best practice for maintaining dental health and software unit testing as a best practice for maintaining software projects. In fact, I believe that the reasons people don't floss may help explain why people don't unit test their software:
Doing it Incorrectly
We can classify how we test software into three categories, Unit Testing, Integration Testing, and System Testing. Compiling code and running it to see how it behaves as a whole is system testing. Writing test code that examines interactions between system resources like a database or DAQ card is integration testing. Writing a piece of code to test the most granular units of your application is unit testing.
It is easy to think of a unit as a VI or a method, but it is better to think of a unit as a single unit of work. A unit of work could be a public member of an API that happens to have several private methods that it calls internally. The unit test would be designed to test the functionality that the public method promises without knowing that any of the private methods exist. This means that if you have 2000 VIs in your project you don't need to unit test each and every one. You only need to unit test VIs that are publicly scoped.
Private methods in classes are implementation details that are consumed by public methods. Testing public methods that call private methods allows us to indirectly test the private method's functionality. There are two benefits here to this approach to testing:
Doesn't Fit the Workflow
There are a few different ways to bring unit testing into your workflow. The least intrusive approach is to start writing unit tests as you refactor an existing code base. As you refactor code you can identify good units for test and start to build up a test suite. Over time you will have implemented tests for the areas of your codebase that are most likely to change, which is exactly what you need.
A more tightly integrated way to add unit testing to your workflow is by adopting Test Driven Development (TDD). In TDD the test is written first and the expectation is that it will initially fail. The developer then writes the minimum amount of code necessary to get the test to pass. TDD makes testing a first class citizen of the design and development process.
Notice that with TDD you will end up writing a test case for every piece of code that you create. This may seem to contradict my recommendation of only testing publicly scoped methods and VIs. In TDD you will use test cases to guide the development of public methods. These public methods will grow as they are written to pass their tests, and through refactoring you will identify parts of public methods that should be turned into private methods. In this way TDD coerces the private methods to emerge within your code very organically.
If both methods A and B have duplicate code that was pulled out and into Method C, then Method C will be a private method used by both A and B. In this situation a unique test case does not exist for method C. However, by testing A and B method C is effectively covered. As long as the all tests of the public interface for our code pass we can be confident that any private methods can be considered an internal implementation detail.
If your current software test strategy involves writing a wrapper around a piece of code and saving it to a folder named "Sandbox" then you have improper tooling. At the very least your tool should automate the running of your tests and generate a pass/fail report for you.
There are three main unit test tools in the LabVIEW ecosystem. The Unit Test Framework Toolkit from National Instruments, the VI Tester from JKI, and Caraya from JKI. You might also choose to build your own test infrastructure. Whatever approach you do decide to take, a solid test framework will make adopting the process easier.
If you are using your own test strategy I would love to know what prompted you to create it! Comment below as to why you favor your approach over the JKI and NI tools.
So is software testing like flossing? I looked for statistics on the number of software developers who do some form of unit testing and couldn't find anything. I put a poll up on my blog and 55% of the people who took part said that they would like to unit test but don't currently do so. If you fall in this 55% I want to know what is stopping you. Just like flossing it will be hard to start. You may even be spitting blood for awhile! However, you will be saving yourself all sorts of pain down the road.
There is plenty more to be said about this topic; check out the list of resources I have included below for further reading. I am also planning on following this post with a tag team discussion of TDD with Russell Blake at G Systems. I would love to get your thoughts on unit testing, unit test tools in the LabVIEW ecosystem, TDD, and your experience with all of the above. If you have anything to add please do so in the comments section below or email me at the link at the top of this page.
I can't wait to hear your thoughts!
Jon McBee is a Principal Software Engineer at Cambridge NanoTech and is a Certified LabVIEW Architect, Certified LabVIEW Embedded Developer, Certified TestStand Developer, an NI Certified Professional Instructor, a LabVIEW Champion, and a Certified ScrumMaster