Setting up Test Driven Development (TDD) with IAR workbench for Embedded C
Updated: Apr 8
Test Driven Development (TDD) is one of my favorite method of development for embedded C. It helps me to have better code quality, less bugs and have more confident about my work. If you are new to TDD and want to learn more about it, make sure to check my recommended resources at the end of this article.
Before we get to this tutorial, there are few important notes:
There are many other ways to setup your Test-Driven Development environment for Embedded C which you can quickly find with one google search.
The following approach is only one of way doing so using IAR Embedded Workbench for Arm. Goal of this article is to have TDD for Embedded C where the following criteria is being met:
* Everything should be kept as simple as possible (not too simple though).
* Both, the production code and test codes shall be maintained under one repository.
* compiling and executing of both test codes and production code shall be accessible with same IDE and the developer can easily switch between the two.
* On-Host TDD (On PC environment or Simulations) and On-Target TDD (on microcontroller) shall be possible with ease.
* and more importantly, the production code and TDD should be completely separated.
So, let’s start:
Start with one of your existing project in IAR Workbench or you can start a new one. I will use one of the ST-Nucleo boards and examples as demonstration here.
The core of any Test-Driven Development method is the Unit testing framework. I use a framework called “unity”. It’s a light weight and great unit testing framework that is designed for embedded software developers in C language. Go to their website and download the unity files. It’s open source and free of charge:
Copy the unity core files to your project folder.
If you have learned TDD from James W.Grenning’s book, then make sure to copy the “Unity Fixtures” also. Using fixtures make life a bit easier, so I highly recommend. Next, let's add a folder called "tests" in our project folder to keep thing seperated. Now, your source code folder should look something like this:
-- scr /* your source code files */
-- unity /* the folder that contains unity core files and fixtures*/
-- tests /* folder that will contain your test cases */
Now, open your project in IAR, import the unity files to the project. Your IAR project workspace should look something like this (Figure 1).
Make sure to add the Preprocessor Path for the unity.
Now, Let’s add the headers to the main. (Figure 3 and Figure 4)
As you can see in the picture, I wrap the hear files and main() into a #ifdef TDD macro, it is because I don’t want to compile anything regarding the TDD in my Release platform and we want to keep things separated (RunAllTests(void) is a function that soon, we need).
Now that in our main.c everything is separated, let’s make a new configuration so that we can toggle between our Release and TDD easily.
In your IAR project .. Go to menu Project -> Edit Configurations ------ press New. and create a new configuration called "TDD"(figure 5).
Having a separate configuration for TDD also gives us opportunity to configure specific parameters in our project option to have better TDD experience. Go to project option and change the following (make sure that TDD configuration is selected).
First add the TDD macro to the Preprocessor (Figure 7).
Reminder: we added the macro wrapper to the main to keep the TDD execution separate.
While you are in "Project option". Go to the "General Option" category and chose "libtary configuration" tab, and make sure to choose the SemiHosted as Low Level Interface Implementation (Figure 8). This will allow us to read the output from Terminal I/O in IAR.
Also, for Debugger, make sure to choose simulator (Figure 9). By choosing simulator, everything will be executed in simulation which is great for TDD. If you want to to TDD on-target then you can set your debugger here so that it will run the program on your micro-controller.
Now we are almost ready, Let’s add RunAllTest, and our first test file (Figure 10, 11).
Create a new file, Called All tests and place the "RunAllTest" in there. (RunAllTest is responsible to run our Test Groups).
(Figure 10, adding RunAllTest file).
(Figure 11, adding our first test)
Now, let's install our first test to the RunAllTest (Figure 12).
Now, Download and debug.
Make sure to go to View -> Terminal I/O to have the view to see the results.. (Figure 13)
(Figure 13, final results.)
Tadaaaaaa.... Congratulation, now you had you first TDD test. As I said at the beginning, this is one way of setting up your TDD environment. The goal is to have all the tools in a single IDE and Embedded development environment.
In our company, I made the TDD standard for majority of our development. It helps us to create better embedded softwares with less bugs and faster delivery time. Hope you find it useful and integrate it in your work flow too.
If you want to learn about TDD, here is few place you can start from:
Book for TDD called: "Test-Driven Development for Embedded C" by James W.Grenning. Read My Review.
Online Course: "Unit Testing and Other Unit Testing & Other Embedded Software Catalysts" by Mark VanderVoord and Mike Karlesky. Link to the course.
To read more tutorials, make sure to check blog section of my website.
To read other reviews and more about my book recommendation, please check my book club: https://www.pouyaneshagar.com/book-club
If you find this article useful, share it so that your friends can also benefit. It would be pleasure to have you as a subscriber, so make sure to subscribe to the newsletter to receive my featured blog posts and book recommendations each month.