Intro to Test Doubles

It’s no secret that many Hollywood actors use stunt doubles. These are specialists that from the outside look and behave like the stars, but have unique talents. The actors do most of the heavy lifting in terms of acting, but for fight scenes, car chases, jumping off buildings, etc. a stunt double is used as a stand-in for the actor. We can apply a similar approach to Unit Testing, by having Test Doubles that resemble our production classes stand in for them during testing.

It looks like Arnold, but is it?

Why use test doubles?

Why would we want to use a test double? There are several reasons. In the LabVIEW world, a major reason is to stand in for hardware. If we want to run automated tests on our build server they need to be able to run without the hardware attached. We can use a test double to simulate the missing hardware. Another reason is cost (in terms of test time or simply complexity). If our test requires an object that represents a whole hierarchy of objects it may take a long time to load or it may be complicated to instantiate. If we don’t need that whole heirarchy of objects to run our test, we can sub in a lightweight test double.

Indirect Inputs and Outputs

The above reasons are all good, but the main reason Test Doubles exist is to test hard to test code. What makes code hard to test? Indirect inputs and outputs. Parameters that are passed via the connector pane are considered direct inputs and outputs. They are easy to access in your test. Simply wire them up. Indirect inputs and outputs are everything else.

Indirect inputs and outputs are not readily accessible in your test code. Indirect inputs are inputs from the environment or external systems; think hardware input, date/time, user input, database entries, system configuration, files, etc. Indirect outputs are side effects: think of hardware output, database entries, files, etc. None of them appear on the connector pane. All of these are often difficult to monitor or manipulate without a Test Double.

Basic Test Double Types

For the purposes of this article, we will talk about 3 basic types of Test Doubles.

  • Responders
  • Saboteurs
  • Spies

Responders

When beginning to write tests, a good strategy is to test the “Happy Path” first. The “Happy Path” is what is normally supposed to happen. The is the path that executes the 90% of the time that everything goes according to plan. Responders make that easy by responding with the normally expected values.

This Responder doubles for a serial port. That status and data that it is supposed to return are preprogrammed. Then when the caller calls the Read method, the correctly formatted string is output.

Saboteurs

As software engineers, we know that things don’t always go to plan. Errors happen, so we write code to handle them. Unfortunately, sometimes it is hard or dangerous to force the code to generate an error so we can test our error handling code. This is where Saboteurs can help out. Saboteurs inject errors and other bad data so we can test our error handling code and make sure our code responds appropriately.

This saboteur simply outputs a timeout error when the caller tries to read the serial port.

Spies

Spies are useful to capture indirect outputs, such as data written to a database or serial port. They simply capture the indirect outputs and make them available to the test code using a queue or something similar.

This Spy simply captures everything that is written to the serial port in a queue that is accessible to our test code, so we can verify that the correct data gets written.

Stay tuned for more

In next week’s post, we’ll talk about some examples of how we install and use Test Doubles.

Leave a Reply

Your email address will not be published. Required fields are marked *

*