Embedded TDD: Freeing us from the Target HW Bottleneck

Img 0759 Phillip Johnston
Embedded Systems Consultant at Embedded Artistry LLC
https://embeddedartistry.com
2018-11-30
@mbeddedartistry

I took a remote TDD training course hosted by James in September 2018. I published a detailed review of what I learned from James's TDD course on my website.

Here, I will focus on how I applied the lessons after the training.

Instant test-runs

We need our tests to be fast and easily runnable if we're going to stick with TDD. I spent a few hours getting my text editor (Sublime Text) to run my unit tests with a keystroke. Now, I press ctrl+B to have my editor save all open files, compile code, and run the unit tests. Results are presented to me within 1 second.

The feedback cycle is so short that I run the tests almost compulsively: ctrl+B has become the new ctrl+S.

Constant Refactoring

Since every module I write now has an associated suite of tests, I can refactor and improve the code without fear of messing anything up. The tests have boosted my refactoring confidence so much that I don't hesitate to rewrite a function if I review a file and find something that's not up to snuff.

Quite often, my changes will inadvertently make a test fail. In the past, these problems would not have been caught until later in the development cycle, and usually by another developer or tester who is trying to use the program. The frequency with which my tests break due to seemingly innocuous changes has been eye-opening - it's so easy to make an innocent mistake.

Improved Designs & Architecture

One of the common problems in embedded systems software is tight coupling between firmware and the underlying hardware, RTOS, and vendor SDKs. Many teams do not spend any time creating abstractions to keep their systems flexible. As a result, designs can quickly become a tightly-coupled house of cards, and the move to a new processor can trigger a total rewrite of software.

TDD has largely improved the design of my systems. Testing also helps us notice coupling problems, especially when a module requires us to pull in the rest of the project in order to test it. By requiring myself to write modules and tests that run on my host machine, I am forced to utilize abstraction layers and prevented from becoming dependent on vendor SDKs. These considerations keep our software flexible and reduce future costs of change.

Driver Development on My Host Machine

Another benefit of creating abstractions which run on our host machine is that we can develop and test our device drivers on our host machines. TDD forces us to write our drivers using generic interfaces instead of chip- and vendor-specific APIs. Mocking allows us to provide data to our device drivers such that we can test the behavior with a given input. Spies and fakes allow us to ensure that other drivers and libraries are being used correctly by our drivers.

Since we've built our drivers with tested interfaces, we will be able to validate the software much more quickly when the target hardware is finally available. Alternatively, with a debug adapter (such as an Aardvark I2C/SPI adapter) and a development board, you can even test your driver on real hardware from the comfort of your host machine.

We've been using TDD to write drivers ahead of hardware deliveries and have drastically reduced bring-up and debugging time as a result.

Breaking the Target Hardware Bottleneck

The perpetual problem for embedded systems developers is the dependency on target hardware. This manifests in a variety of ways: waiting on hardware before beginning development in earnest, inefficient workflows due to slow flashing times, difficulty debugging problems, and not having enough hardware to go around.

The TDD approach enables us to begin developing our firmware before hardware is ready, and can keep teams moving forward even if hardware is scarce. We can get a jump start on development and write code that can be quickly and confidently ported to the target platform once we are able to work with hardware. To me, this is the greatest benefit of the TDD approach.

Final Thoughts

I didn't expect that James's TDD course would have such a large impact on the way I develop code. The hands-on exercises got me comfortable with the process, and once I configured my environment to make it easy to running tests, I never stopped.



All Stories
We invite you to submit your own story about TDD or Agile for Embedded System Development.
  • Wingman Alumni can sign into their account then return our stories page to add your story.
  • Others, contact for access to add your story.
  • Don't feel like you need to give us a plug (thanks in advance if you do). This is about your story.