In a recent tutorial we wrote at Beetlebox, we explored Test Driven Development (TDD) for Field Programmable Gate Array (FPGA) technology. We wrote a small section on what TDD is and how it could benefit FPGA designers. In this article, we are going to expand on that theme and talk about how TDD can benefit the Internet of Things (IoT) as a whole.
TDD is a software development process in which automated tests are written prior to the actual code. This allows developers to identify problems early on and ensure code is of the highest quality. We will cover the advantages IoT engineers can gain from TDD. We will also look at how we can combine Continuous Integration (CI) with TDD for a practical setup.
Introduction to Test Driven Development (TDD)
TDD is a software development process in which tests are written prior to writing any actual code. This encourages developers to think more carefully about the design of their code and functionality. A designer will need to consider not only what inputs are available, but also what the needed output is before a single line of code is written. This helps identify potential problems before they are found further down the line.
The three phases of TDD are:
- Write a test: The developer writes a simple test that describes the desired behaviour of the code.
- Run the test: The developer then runs the test to see if it fails.
- Write the code: Finally, the developer writes the code to make the test pass.
Once the code is complete, the developer can rerun the test to ensure that it is working as expected. If the test fails, the developer can go back and troubleshoot the code until the test passes.
Benefits of TDD for the Internet of Things (IoT)
The IoT is a network of connected devices that share data with central servers called the Cloud as well as amongst each other. The IoT is made up of millions of physical devices, such as sensors, cameras, RFID tags and more. These devices are powered by an embedded system, which generally will have a microcontroller or microprocessor controlling communications and data processing.
Properly validating code on the IoT is incredibly important. The IoT forms of network of servers and devices that rely on each other. Bugs can result in a breakdown of the network, meaning that a bug that occurs on a single device may end up breaking an entire service.
On top of this, connectivity of devices is not always guaranteed. A device may be operating in a remote region or may be temporarily unavailable whilst in transit (i.e. a smartphone in a tunnel). We need to be confident that these devices function correctly before it is deployed because it may be an unknown amount of time before it can be connected again and updated.
In extreme cases, a new update may end up breaking the device completely or ‘bricking’ it. TDD lessens the chances of this happening by ensuring that all deployed code is tested before release.
Finally. TDD can also increase the rate of updating devices. If we write additional code for our devices, we can use the pre-existing tests to ensure that the new code does not break functionality. This increases developer confidence, so updates can arrive sooner.
Combining TDD with Continuous Integration (CI)
Making TDD practical requires CI services. Continuous Integration is a software development practise where developers regularly contribute code into a single codebase. Automated pipelines then run builds and tests against that codebase to ensure the system is working correctly.
A strength of TDD is that it quickly builds up a suite of tests to check the functionality of our devices. We cannot, however, let this suite of tests bog down development. If a developer is left needing to run an hour worth of tests every time they want a new feature TDD will quickly be abandoned.
CI can prevent this from occurring by automating the test suite and allowing the developer to focus on coding without manual managing the testing process. The first step is for the developer to setup a version control system, such as GitHub, GitLab or Bitbucket.
As shown in the diagram above, in a combined CI and TDD, a developer will get a request for a new feature. They will first write their tests for that feature, but they will not manually execute these tests, whilst developing. Instead, they will place these tests inside an automated pipeline inside the CI service.
Once this pipeline is setup, the developer will then write code as before, but instead of executing tests, when they have finished, they will instead commit code to their version control system. The change in the code will automatically trigger the pipeline to run the suite of tests on a separate server. Thus, ensuring that the tests never bog down the developer, whilst still gaining the benefits of TDD.
Putting it all together for the IoT
By combing TDD and CI for the IoT, we can build a robust framework for our IoT projects. TDD and CI combine together naturally because CI can effectively automate the tests that TDD will need to run on a regular basis.
We can then develop efficient pipeline that are able to build and test all parts of the IoT infrastructure, from the software running on the embedded systems through to the servers the devices communicate with. When updating devices, developers can be more confident as they can test the impact of their code on all parts of the systems through the tests they made as part of the process.
By keeping to the process of writing a simple test, then writing just enough code to pass it, developers have a robust way of finding bugs early, releasing faster and being more confident in their designs.