Sunteți pe pagina 1din 44

EMBEDDED

CMock & Unity


Primary Developers

TESTING
Mike Karlesky
Mark VanderVoord
Greg Williams

A Book For Those Who Code C Original Framework Creator

UNITY &
And Want Awesome Well -
WITH

Te s t e d P r o d u c t s Bill Bereza
U s i n g F r e e To o l s

CMOCK
And For Those *
Who Enjoy Short
Books With Long Writing, Art, & Design of this
T i t l e s • by Mark VanderVoord • 2010 • Mini-Book

This Mini-Book attempts to show how the tools CMock and Unity can be used to Mark VanderVoord
unit test C projects. These tools were built because Test Driven Development was
tedious without some automation and nothing like them existed for embedded *
development. There is really no reason that these tools are limited only to
embedded software, nor any reason that you must do Test Driven Development Also Thanks To
to use these tools for testing... but we’ll think you’re extra cool if you do.
All who have submitted
It would be seriously Awesome if we could fill 40 pages with cartoons, and patches, ideas, and questions,
you would then be a code-fu master and ready to use all the techniques and especially Martyn Jago
tools involved. It would also be cool if we could put all this information on an
embedded processor which could be plugged into your brain, giving you instant *
access to our combined knowledge. Since neither of these are very likely, feel
free to post to the forums for either project. Images not created by Mark
(Creative Commons Licensed)
This Book is Released Under Creative Commons
Attribution-Noncommerical-Share Alike 3.0 Jason Rogers (x-ray on pg11)

<1>
You’ve started reading this This is a story about one evil has watched them fail over
book, which means you genius, possibly quite like and over and over and over
like open source tools, yourself. (otherwise what’s again.
are interested in Agile the point?)… the infamous Dr.
development, write code for Surly. But not Dr. Surly. No… Dr.
embedded software, work Surly knows what to do. He
for an evil genius, are an evil Dr. Surly is… well surly… knows good practices and
genius yourself, or possibly because all the awe-inspiring knows how to make things
all of the above. Well, you’re villain names (Dr. Horrible, happen. He will build the
not alone… clearly there are Dr. Doom, Dr. Evil) have been ultimate program to take
others out there who… at trademarked well before he over the world, and it will be
a minimum… work for evil was even born. tested and foolproof! No bug
geniuses or are evil geniuses. will dare stand in his way…
He knows it is his destiny to nor will his meager budget.
be great… a giant… a pillar No unexpected behaviors will
of… er, darkness, in the unfurl tiny banners of defeat…
community of evil-doers. But nor will using C keep him from
how will he ever accomplish injecting serious doses of
such a feat without an Awesome into his work.
Awesome (yes, with a capital
“A”) villain name? Muwahahahahahahah!

So his surliness has festered A quick search on the internet


through the years, growing and he wrings his hands with
nasty tendrils and tentacles glee. Yes, he has found it. A
around his brain. His surliness simple unit testing framework
has spread like a tumor, until it for C, Unity. It’s been used
exploded as a dastardly plan with gcc, IAR, Green Hills,
in his head. He will exact his even Visual Studio... This will
revenge upon the entire world. surely help him.

Dr. Surly is no idiot. He has unity.sourceforge.net


seen other villains fail before
him. He has witnessed their It’s site is kinda lame, but
glorious plans dissipate due otherwise it seems a good
to tragic unforeseen flaws. He tool.

<2>
“Ah well... take solace little Dr. Surly knows that his How exciting! Unity has just
test framework, I will seek project will grow over time... tested itself and reported
vengeance against those who But he also believes in doing itself to work just fine with his
have wronged you this way... ‘The Simplest Thing That SurlyC compiler.
work with me, and you will Could Possibly Work.’ For
achieve vengeance!” now, he won’t worry about Wait a minute... the docs say
setting up dependency that if he runs the ruby builder,
Dr. Surly peruses the website, tracking for his project or it will also test an example
learning about the simple little other such frivolities (even project. He tries it real quick,
framework and his options. though the gruesome out of interest. After updating
Does he download the cutting complexity of such things the yaml file, he runs:
edge release with subversion make him giddy).
or just take the latest stable >rake
release? Either would work, Being the careful sort, Dr.
but he opts for stability. Dr. Surly lays out a little map A quick spattering of tests fill
Surly’s plans are dastardly of the directory structure of the screen.
enough without taking on Unity, to remind himself of
additional risk. what’s what. auto – a collection of Ruby
scripts which make using
He downloads the latest Excellent. He opens a Unity less painful
release and reads the docs. command prompt and types:
He is relieved to find that build – ignore this. Temporary
Unity is pure C. He’s a C >make build files go here.
man... he doesn’t mind letting
the included Ruby tools add An error!? How could that docs – wonderfully
some Awesome... but he’s be? He opens the makefile entertaining docs
not interested in learning and looks. Ah... a little
another language. Let’s see... tweaking is required: examples – examples of how
1.9.2 is recommended? He to use Unity
goes to ruby-lang.org and C_COMPILER=SurlyC.exe and it’s scripts.
downloads the one-click SYMBOLS=--defineTEST
installer. src – where Unity lives
and then
“Let’s get you running, little test – tests using Unity
friend.” >make which actually test Unity
itself.

<3>
“Enough delay!
Now is a time for
ACTION!”

Great! He starts by using one of the handy scripts to create


the module for him. He could create a source file, header file,
and test file by hand, but why not just let the script do it?

>ruby generate_module.rb MenacingLED


Dr. Surly shouts with glee!
created MenacingLED.c
His pet sloth, Sourpuss slowly created MenacingLED.h
opens his eyes, annoyed created TestMenacingLED.c
that the outburst interrupted
a perfectly nice dream... a Glancing at his schematic, he sees that he planned his
beautifully recursive dream menacing LED to be on bit 1 of port A. So he’ll have to create
where he was dreaming about a function which sets that bit to an output and initializes it
dreaming. Sourpuss casts to high. He knows it’s usually best to test a single module
Surly a withering look, then at a time, so he gets to work on that... He’ll start by writing
adjusts his hold on the twig one or more tests to describe how that function should work.
before falling back to sleep. Updating TestMenacingLED.c, he creates his first test function:

Dr. Surly ignores the creature, #include “unity.h”


instead thinking of a simple #include “MenacingLED.h”
feature... one suitable for void test_MakeSureLedTurnsOnMenacingly(void)
familiarizing himself with his {
new ally. Eureka! No Device PORT_A_DIR = 0xFF; //1’s are inputs
Of Sufficiently Evil Intent PORT_A_OUT = 0x00; //start with all bits 0
would be complete without a MenacingLed_Init();
mysterious menacing LED... a TEST_ASSERT_EQUAL_HEX8(0xFD, PORT_A_DIR);
RED LED! TEST_ASSERT_EQUAL_HEX8(0x02, PORT_A_OUT);
}

<4>
There are also empty functions setUp(void) and tearDown(void) He then types in the
in the generated C file. He leaves those alone for now, though command to have SurlyC
in a more complicated module these may come in handy. compile and link the test,
runner, source, and unity
This looks like a pretty good test. He starts by filling memory files. Then he runs the output
with data that is clearly not what he wants it to be. He then executable:
calls the function to be tested. Finally, he verifies using the
TEST_ASSERT statements that everything was configured as it >Test
should be. This pattern of setting up, calling the source to be
tested, then verifying is a common pattern when writing unit ---------------------
tests. UNITY FAILED SUMMARY
---------------------
He needs a few more things before he can run the test. He C:\projects\surly\
adds to MenacingLED.h: TestMenacingLED.c:6:
test_MakeSureTheLed
#include “MicroRegisterDefs.h” TurnsOnMenacingly:
#define MENACING_LED_MASK (2) FAIL: Expected 0xFD was
0xFF.
void MenacingLed_Init(void);
---------------------
...and a skeleton of the function under test should be enough in UNITY TEST SUMMARY
MenacingLED.c: ---------------------
1 Tests 1 Failures 0
#include “MenacingLED.h” Ignores

void MenacingLed_Init(void) { } The summary at the bottom of


the output shows that a single
He goes to the command line and types: test was run, as expected.
It also shows that this test
>ruby generate_test_runner.rb TestMenacingLED.c failed.

He grins a wicked grin as he sees a TestMenacingLEDRunner.c Each failure is given more


file appear in the output directory. The script scanned his detail in the “Failed Test
test file for functions of the form “void test___(void)” and Summary” earlier in the
automatically set up a file to call each of these and collate output, so he reads the item
results. listed there.

<5>
It has informed him that line 6 of TestMenacingLED.c failed. If he was going to have a
Glancing at line 6 of his test, he notices that it contained an number of these tests, he
assertion to verify that PORT_A_DIR had been set properly. could reduce some of the
Oh yes! Of course it failed the test! He didn’t write the actual redundancy by creating
source code yet. a helper for the register
initialization, the assertions
Now that he has shown that the test catches a problem with at the end, or both. Since
his source code, he writes the minimum amount of code that everything is straight C code,
should make the test pass: he is completely free to create
new functions in his test file
#include “MenacingLED.h” that can be used to reduce
duplication. The only rule is
void MenacingLed_Init(void) that those functions shouldn’t
{ start with the word “test” if
PORT_A_DIR &= ~(MENACING_LED_MASK); you’re going to use helper
PORT_A_OUT |= (MENACING_LED_MASK); scripts.
}
void
Rebuilding and rerunning the test, he cackles. One step closer InitializePortA
to world domination! ( uint8 ADir,
uint8 AOut )
1 Tests 0 Failures 0 Ignores {
PORT_A_DIR = ADir;
He’s pretty sure that his code is correct, but he remembers that PORT_A_OUT = AOut;
he should verify that none of the other bits are being effected. }
So, in addition to his existing test, he adds:
Now he can use this function
void test_MakeSureTheLedTurnsOnWithout where ever he needs to
TouchingOtherPins(void) initialize his ports. This
{ function won’t be run by itself
PORT_A_DIR = 0x00; //opposite other test as a test because it doesn’t
PORT_A_OUT = 0xFF; //opposite other test start with ‘test’.
MenacingLed_Init();
TEST_ASSERT_EQUAL_HEX8(0x00, PORT_A_DIR);
TEST_ASSERT_EQUAL_HEX8(0xFF, PORT_A_OUT);
}

<6>
WAIT! HOW DID HE DO THAT? Your goal is to position so our test version looks like:
registers somewhere where it
This is one of the classic is safe to write and read. You UART_T UART3;
questions about unit testing don’t want to have to change unsigned short P3;
embedded code: How do you much of your main code,
test registers? Ideally, you’re though, so it’s all about how NON-STANDARD C
not running real hardware here the registers get defined. First, Some compilers have some
(that’s for system tests). You look at the micro’s register extra “goodies” where they
are most likely running either a definition file. Sometimes it’s have support for a specific bit
simulator (getting to use your a bunch of structs placed in of that port... It’s a shorthand
real compiler) or using a native certain locations... sometimes a and it’s not really C.
compiler to compile native test bunch of defines. We’re going
apps (probably faster). to copy this file and make P3 |= 0x01; //normal C
one that is used only for tests. P3_0 = 1; //not normal
SIMULATORS When you build your release,
This is the easiest situation. you’ll still use the original, but That’s very nice of them... but
Most simulators will let you tests will use this new one. It’ll harder to test with a normal C
write to any memory, so you be work, but it’s going to make compiler (like gcc). There are a
can fill it with something invalid, testing so much easier! couple of options:
run your function, then use
TEST_ASSERT functions to For those registers defined 1. Avoid the bit-sized operators
verify that the contents were in structs, just remove the and stick with entire ports.
updated as you expected. Easy. location specific part of the
definition so that the linker will 2. If you really want to use
NATIVE just create it somewhere. those bit-operators, it’s best
Let’s say the testing is a if you ALWAYS use them,
native executable on your When you’re dealing with a instead of mixing and matching
development machine instead. pointer de-reference define, between P3 and P3_0 uses.
You can’t exactly just write replace it with an actual You’re going to create a full
to any memory location you variable... it’ll then get mapped byte-size variable for every
want and assume it’s going somewhere safe by the linker. single one of those bits.
to be ok (address 0x1234 Remember, only in your test:
might be the LED port on your #define UART3
micro, but I bet it’s not on your (*(UART_T*)0x3000) unsigned char P3_0;
development PC!). #define P3 (*(unsigned unsigned char P3_1;
short*)0x4000)

<7>
Basic Assertions Automatically Ignore or Fail

TEST_ASSERT_TRUE (condition) TEST_IGNORE( )


TEST_ASSERT(condition) TEST_FAIL( )
evaluates code in condition and
fails if it evaluates to false
TEST_ASSERT_FALSE (condition) Integer Assertions
TEST_ASSERT_UNLESS(condition)
evaluates code in condition and All of the following compare types
fails if it evaluates to true. of integers. They vary in how the
data is displayed to the user on Pointer Comparisons
Structs and String Assertions failures.
TEST_ASSERT_EQUAL_PTR(E, A)
TEST_ASSERT_EQUAL_STRING(E,A) TEST_ASSERT_EQUAL_INT (E, A) TEST_ASSERT_NULL(A)
TEST_ASSERT_EQUAL_MEMORY TEST_ASSERT_EQUAL_UINT TEST_ASSERT_NOT_NULL(A)
compares two blocks of memory TEST_ASSERT_EQUAL_HEX8
using memcmp. It takes args TEST_ASSERT_EQUAL_HEX16 _MESSAGE
(E, A, L) where L is the length TEST_ASSERT_EQUAL_HEX32 add this to any of the
(you could use sizeof) assertions to pass in an
These assertions verify that the extra string argument at the
Bitwise Assertions number actual number is within end when failures are printed.
plus or minus delta of the
TEST_ASSERT_BITS (M, E, A) expected value. _ARRAY
compare two numbers, only add this to any of the int or
bits marked 1 in the mask TEST_ASSERT_INT_WITHIN(D, E, A) float assertions to test an
TEST_ASSERT_BITS_HIGH (M, A) TEST_ASSERT_UINT_WITHIN entire array of values. The
evaluates true if all 1 bits in TEST_ASSERT_HEX8_WITHIN args are then (E, A, N)
mask are 1 in the actual data TEST_ASSERT_HEX16_WITHIN
TEST_ASSERT_BITS_LOW (M, A) TEST_ASSERT_HEX32_WITHIN E - expected value
evaluates true if all 1 bits in A - actual value
mask are 0 in the actual data Float Assertions D - delta
TEST_ASSERT_BIT_HIGH (b, A) (if you have them enabled) M - mask
evaluates true if bit is high N - num elements to check
TEST_ASSERT_BIT_LOW TEST_ASSERT_EQUAL_FLOAT(E,A)
evaluates true if bit is low TEST_ASSERT_FLOAT_WITHIN(D,E,A)

<8>
Looking through the list of UNITY_INT_WIDTH can be UNITY_FLOAT_VERBOSE
assert macros, Dr. Surly used to specify the number can be defined to make Unity
notices that the floating point of bits that make up an print the expected and actual
asserts are optional. This INT. C is a crazy language, values for floats, similar to
makes a lot of sense to sometimes... Some targets the way integers failures are
him... Unity grew up amongst have 16 bit ints, some 32... reported. Ordinarily the float
embedded applications, many Unity defaults to 32 bits, but itreporting is turned off to avoid
of whom don’t have floating also supports 16. bringing in heavy functions
point support. It would like printf. If you’ve got the
be sad if Unity broke just UNITY_POINTER_WIDTH can resources, though, add this
because the compiler didn’t be used for when you want to define for useful output.
know what a ‘float’ was. do pointer comparisons. This
is particularly helpful if you Everyone knows that you
It appears that he can disable have 64 bit pointers instead of can’t compare two floats for
floating point support by the default 32. equality directly, so TEST_
adding a single define: UNITY_ ASSERT_EQUAL_FLOAT
EXCLUDE_FLOAT. Probably UNITY_FLOAT_TYPE is doesn’t do that. Instead, it
the easiest method would usually defined to be float, but checks to make sure that the
be to add the define as one you can change it to double two values are within a delta
of the command line options, or whatever wacky floating of each other. The delta is the
but any method should work. point types your compiler expected value times UNITY_
might support. Why float? FLOAT_PRECISION, which is
This makes Dr. Surly curious, Again, Unity grew up with 0.00001 by default.
though (Evil Geniuses are embedded developers, whose
almost universally curious. systems are single precision.
They also have compulsive
need to monologue at Curiosity Parts Per Gram
inconvenient times... but
that’s not particularly relevant
at the moment). Anyway, Dr. babies
Surly is curious about Unity’s
options now. What else can
he customize? cats

evil geniuses

<9>
UNITY_SUPPORT_64 can UNITY_OUTPUT_CHAR(a) RESULTS
be defined to enable 64-bit is a macro that you can Since we’re on the subject,
comparisons. You will also use to change how Unity what is the best way to gather
want to define UNITY_LONG_ outputs data. Ordinarily, it the results from Unity? That
WIDTH to 32 or 64 to give uses putchar to output to depends on two things:
Unity a clue how to get 64-bit stdout. This works for many
support. applications. A test run as an What do you need?
app can just dump result data
You can even change the to stdout and you can look If you’re just manually running
types of internal variables. at the output yourself, pipe these tests, dumping all the
Both are unsigned shorts it to a file, or whatever you results to stdout is probably
by default... which works might need to do. Similarly sufficient. Often, automated
for most applications. But if many simulators will forward systems like Continuous
you have an insanely huge their stdout to the calling Integration servers are
file or many tests in a single environment. But maybe your flexible enough to handle this
file (65535 lines or 65535 simulator doesn’t support too. If you’re using Unity’s
individual test functions, this or you have to run your automagically generated
respectively), you can adjust code on actual hardware... for test runner, your test exe will
either UNITY_LINE_TYPE for those with issues like these, return the number of failures
the number of lines or UNITY_ this macro will be your friend. as the exit code (0 being that
COUNTER_TYPE for the they all pass, and the number
number of tests and failures. saturates at 255 to avoid
If you’re a memory miser and platform issues). If you need
can get away with less than something fancier, maybe
255 of these, you can save a that UNITY_OUTPUT_CHAR
tiny bit of memory by lowering macro needs some attention.
these down to unsigned
chars. Setting these values What can your target handle?
might also help you if you run
into memory alignment issues Sometimes your simulator
with some targets. might not allow you to
capture its output or other
such difficulties. It might be
time to consider testing using
gcc and saving your real
compiler for the release build.

< 10 >
ANATOMY OF A TEST
Tests are a bunch of functions Unity Project Structure
and files that have been Unity mostly consists of A good way to layout a
splatted together and ASSERT macros which you project is to have
executed. Here’s a quick can use to verify that the all the tests in an adjacent
overview of those parts. results of your function calls directory... maybe even call
are as you expect. You could that directory ‘test’ and
Source File use TEST_ASSERT_TRUE do something crazy like
One of the things built into for everything, but there are name the test file for source
this mix is the source file that many more options which MyCode.c something like
you want to test. Instead will output more helpful TestMyCode.c.
of linking this to the rest of information on errors.
your source, though, you’re If you like that sorta thing, you
linking it to a test file and Test Runner might like some of the other
some supporting modules, If you’re using the helpful helpful scripts that come
allowing you to just verify that Ruby scripts, you’ll have a with this project. The script
this source file works as you Test Runner automatically to generate a source module
expected. Do that for each generated for you. It looks will create a C file, header file,
source file in your system, through your test file, finds and test file from a base name
and you’re Unit Testing. all the functions that look that your provide. There are
like tests, and creates a others that will do similar
Test File main( ) function for you. This things but match some design
The test file contains a bunch function manages all the calls patterns... someone is bound
of functions in the form of to tests, setUp, and tearDown. to bring up design patterns in
void test_blah(void). Each If you’re not going to use the this book somewhere.
function that matches this scripts, check out the page
form will be executed as on Anti-Scriptites.
a test. It also contains a
function setUp(void) and Executable
tearDown(void). The setUp Take the source file(s), test
function is run before each file, unity, and test runner
test, and the tearDown and compile each. Link their
function is run after each test. object files and you’ve got
You can use these to make a test exe for this test file.
sure any shared variables are You’ll end up making an exe
in a known state, memory is for each test file you have.
cleared, etc.

< 11 >
Software developers come in all shapes and sizes. Since we’re mostly geeks, most of those
shapes and sizes aren’t particularly attractive, but we make up for that by being Awesome. The
only trouble is, the definition of Awesome may vary from person to person. For example, some
developers believe Awesome is being in complete control and understanding every detail. Let’s
call them the Anti-Scriptites. Then there are the Script-O-Rama-Lings, who have the goal of
avoiding as much of the tedious work as possible and concentrating on the real features. Here’s
some thoughts on how Unity can work for either of them.

A N T I - S C R I P T I T E S ! S C R I P T- O - R A M A - L I N G S !
You don’t need to use any of the supplied Those scripts that come with Unity aren’t
scripts to use Unity. You will, however, need to bad... but you’re still left collecting a test
manually create a runner for your tests, calling file, runner, and supporting files together,
each one. Set up a main function for each test compiling, linking, running, collecting results,
file to actually call all those crazy test functions. then repeating with the next file... whew!
It’s easiest if you put main together something Tedious! If only there were a way to just
like this: throw files in standard directories and let the
magic of dependency tracking just do the
void main(void) { rest. You could sit back and tweak yaml:
Unity.TestFile=__FILE__; :project:
UnityBegin(); :build_root: projects/mine
RUN_TEST(test_init); :use_exceptions: FALSE
RUN_TEST(test_set); :use_mocks: TRUE
RUN_TEST(test_three); :paths:
UnityEnd(); :test:
} - test
:source:
That RUN_TEST thing is a macro defined by - src
Unity. If you’re doing a lot of custom handling :include: []
with your tests (adding code coverage, :tools:
mocking frameworks, etc) you might need :test_compiler:
to redefine that. Just make sure it is defined :executable: gcc
before the include of Unity.h, and it’ll use your
version instead. You might want to look at the If this sounds nice, you might consider
standard implementation first, though... That Ceedling, a build and test framework using
TEST_PROTECT is crucial, unless you enjoy a Ruby and Rake. Point your web browser to
good segfault. ceedling.sourceforge.net.

< 12 >
Meanwhile, hundreds of miles away, we find a bustling metropolis. Far, far below the city lies a
secret bunker. In this secret room, we find two lone figures staring at a computer screen. The short
pink one grunts a curious grunt, his chubby hooves poking at the keys.

“What is he doing?” “It appears (grunt) he has developed


his first feature...
asks the billed one.
a maniacal plan,
no doubt.

He’s developing one feature at a time, cutting from top to bottom


Like an I2C Driver? instead of developing in traditional layers.

That’s more of a task.


“So a version command? Feature.
... ... ... ... huh? watchdog timer? Task.
resets itself if problem? Feature.
makes coffee? Feature.
reads ADC? Task.
measures noise? Feature.
ThunderDuck
Underpants? .... uh

< 13 >
Insane! He’ll break his ...unless he finds a test Not with Dr. Surly!?
existing code whenever framework to protect him. Open Source?
he makes changes!
I’ll call the
others...

.
Dr The Super Scary Screaming Shrieking Siren!*
e ? his un
tim d by beg re
h ere tere has eatu
t , f
s ols s d
u t i y, b ccess 2n
l
B ur su h i
S st on
la ork
w
* or s5 for short

He already has all the s5 hardware hooked up... he just needs While he ponders, he hears a
to drive the onboard Timer-Counter peripheral to generate a little voice, “CMock.”
horribly painful frequency... and maybe scan a digital port to
use as an on/off control. “Excuse me?” asks Dr. Surly,
startled. He looks around the
This is a bit more complex than his menacing LED. He would lab, but only finds Sourpuss
really like to break it into multiple modules... maybe a sub- napping between the beakers.
module for button scanning, one for frequency generation?
Something like that. “I think,” says the voice, “You
should check out CMock.”
Testing the Button module or the Frequency module seems
simple... it would work like his LED module. But what about Dr. Surly stares at the screen,
his S5 module? It mostly calls those other two... how does he “Unity? Are you talking to
test that? me?”

< 14 >
“Yes,” responds the framework. Sourpuss continues to stand The sloth opens one eye,
firm with apathy. briefly, then yawns and
Dr. Surly wonders if perhaps returns to sleep.
he has been working too long, “Don’t you see? This tool is
but jumps onto the internet going to allow me to break my “On my own, I see,” Dr. Surly
anyway. A moment later, he code down naturally without grumbles.
has downloaded the latest having to get it all working
release of CMock from cmock. at once! Plus, it’ll be fully “Hardly,” says a pair of voices
sourceforge.net. tested!” from the computer.

“Yes,” Dr. Surly laughs, “This


is exactly it, Sourpuss,” (who
ignores him), “This tool will
automatically create Mocks
for me.” config - configuration used for some
of CMock’s self-tests.
When the sloth doesn’t
respond, Dr. Surly assumes docs – more wonderfully
he needs further clarification, entertaining docs
“Mocks are fake versions of
an entire module. I have a examples – examples of how to use
module I want to test, like CMock and it’s scripts.
S5. I have modules that it
interacts with, like Frequency lib – where CMock keeps its guts
and Buttons. Instead of
testing them all together, I test – CMock comes with lots of tests.
can test S5 by linking it to It unit tests itself, plus can run
Mock versions of the other comprehensive system tests to
two. With the Mocks I can verify it works with your tools
verify that functions get called
when I expect them to, that vendor - these are the libraries that CMock
they were called with the uses. You’ll even find Unity here!
arguments I desired, and I
can even use them to return
whatever results I want to
test!”

< 15 >
Dr. Surly starts by creating an S5 module with a script call: He also puts a prototype
for S5_Exec in S5.h, and an
>ruby generate_module.rb S5 empty implementation in S5.c.
That should be enough to
He cracks open the test file and begins to insert tests. The run a test. He lets it compile,
CMock manual said to set up all expectations before calling link, and run. The test returns
the function being tested. He wants to make sure that the s5 is a single failure, described
silent when the switch is off (no sense deafening himself). So, as “Function ‘Buttons_
he creates a test: CheckS5Switch’ called less
times than expected.”
#include “MockButtons.h”
#include “MockS5Ctrl.h” Well that makes sense. Since
S5_Exec() is just an empty
void test_S5_Exec_ShouldBeSilentWhen0(void) function so far, the test has
{ correctly informed him that
Buttons_CheckS5Switch_ExpectAndReturn(0); he had expected Buttons_
S5Ctrl_Silence_Expect(); CheckS5Switch to be called,
but that it was never was. It
S5_Exec(); quits each individual test at
} the first sign of trouble, so
it hasn’t yet noticed that
Yes, something like that. He expects that the s5 switch will be S5Ctrl_Silence also hasn’t
checked, and it will return 0 for the purpose of this test. Seeing been called.
the 0, the exec function should then call for silence. Then the
test runs the actual function to verify that all the expectations Well, now that he has a failing
have occurred. test, it must be time to write
enough code to make it pass.
He doesn’t need to make the Mock header files himself, He turns his attention to his
CMock will handle that for him. But he does need to make S5 module. In particular, Dr
sure that they are included in the test (which he has done) and Surly writes the S5_Exec
he needs to ensure that the real headers exist and have proper function, ignoring the fact that
prototypes. Buttons_CheckS5Switch and
S5Ctrl_Silence still do not
He uses the scripts to create a couple more modules actually exist.
(Buttons.c and S5Ctrl.c). He puts a prototype for Buttons_
CheckS5Switch and S5Ctrl_Silence in the correct headers.

< 16 >
The exec function should be simple enough. It needs to check the He updates his function to
switch to see if the level is low (zero). If so, it should configure the support the new feature:
system for silence. Easy enough. He types:
void S5_Exec(void)
void S5_Exec(void) {
{ if (Buttons_CheckS5Switch())
if (Buttons_CheckS5Switch() == 0) {
{ S5Ctrl_SetFrequency(20);
S5Ctrl_Silence(); S5Ctrl_Loud();
} }
} else
{
He reruns the test, this time seeing that everything passes. OK, so next S5Ctrl_Silence();
he would like an extremely loud screech at 20KHz when the button is }
pressed. So, he adds a test for that: }

void test_S5_Exec_ShouldBePainfullyLoudWhenSwHigh(void) He runs the test again,


{ expecting everything to be
Buttons_CheckS5Switch_ExpectAndReturn(1); fine... but... what? A failure?
S5Ctrl_SetFrequency_Expect(20000);
S5Ctrl_Loud_Expect(); Expected 20000 was
20. Function ‘S5Ctrl_
S5_Exec(); SetFrequency’
} called with unexpected
value for argument
He grumbles with annoyance when he hits compile and is reminded ‘Frequency’
that he needs to add a prototype of S5Ctrl_SetFrequency(Frequency)
and S5Ctrl_Load() to S5Ctrl.h. Ah! He goofed up the units.
He wanted 20KHz (or 20000
Dr. Surly is persistent, though, and knows it will become second nature. Hz), not 20Hz!
He adds the prototypes and nothing else. Running the tests, he sees
the expected failure: “Function ‘S5Ctrl_SetFrequency’ called less times
than expected.” The exec function hasn’t been designed to actually
call the new functions yet.

< 17 >
He corrects the function to pass 20000, and updates the name of the argument to ‘Hz’ instead
of ‘Frequency’ to clear things up in the future.

He also realizes that he really only wants the “loud” setting engaged when the frequency was
properly set. He updates the S5Ctrl_SetFrequency function to return the actual frequency. This
requires him to change the Expect in his last test:

S5Ctrl_SetFrequency_ExpectAndReturn(20000, 20000);

He also adds a new test to capture the new behavior. In this test, he expects that S5_Exec will
request 20KHz, but his mock of S5Ctrl_SetFrequency will return only 14KHz, enabling him to
test what would happen:

void test_S5_Exec_ShouldBeSilentIfNotLoudEnough(void)
{
Buttons_CheckS5Switch_ExpectAndReturn(1);
S5Ctrl_SetFrequency_ExpectAndReturn(20000, 14000);
S5Ctrl_Silence_Expect();

S5_Exec();
}

Of course, it fails when he runs the test, because S5_Exec is still ignoring the return value and is
calling S5Ctrl_Loud. He updates the function under test:

void S5_Exec(void)
{
if ( (Buttons_CheckS5Switch()) && (S5Ctrl_SetFrequency(20000)) )
S5Ctrl_Loud();
else
S5Ctrl_Silence();
}

There. That’s better. Honestly, Dr. Surly is feeling a bit better knowing that he has tested all
these conditions in a robust manner.

< 18 >
AN ASIDE ABOUT
ZOMBIE HORDES

At one time, zombies were


a real problem. They’d
stumble into your office and
suddenly half your coworkers
were brainless (assuming
they weren’t already)! The
only solution was a stick of
dynamite or a shotgun, not
exactly common in an office.

Thanks to modern technology, Or choose one of the have seen a lot of ugly legacy
those days are past. Each following forms from Ruby or code and poor libraries. They
instance of CMock comes Rake, then use it: pride themselves on being
with its own tiny zombie able to parse your headers,
horde, carefully trained for #uses defaults no matter how ugly the code
your convenience. When you m = CMock.new is. But, if you fear they may
think about it, it’s a perfect #specifies YAML file need help (zombies aren’t
match. You get the tireless m = CMock.new(YamlFile) exactly known for their
work ethic of the undead #specifies directly intelligence), CMock has a lot
while they get to drool over m = CMock.new(OptionsHash) of configuration options.
large engineer brains. It’s #use it!
beautiful, really. m.setup_mocks(FilesToMock) They then piece together a
Mock (fake) version of each
Exactly what can you do with Either way, the zombies start function. Just as zombies
a zombie horde? Try this to gnawing on the header files, are mutated shells of original
find out: call CMock from picking out all the function people, so Mocks are
the command line, optionally declarations that can be zombified shells of the original
passing the path to a yaml file found. But don’t worry... functions. On the surface, it
containing options: they’re working for you. looks mostly like the original.
Maybe its pallor is more gray...
> CMock (-oYamlFile) Files Some zombies are really old its gait a little crooked. But
(the ones with more missing inside, things are completely
body parts). Old zombies different. The insides don’t

< 19 >
care about real-life things... const - Attributes like ‘const’ attributes - Some compilers
instead they care only about will appear in your Mock support non-standard
simple things. They count the just like the original function, attributes like ‘__irq’ or ‘input’
number of times you expect but might be dropped from in functions or arguments.
functions to get called, and Expects to make testing easier. If you add these to the
groan when that doesn’t :attributes list, you can give
happen. They make sure extern - Any function those zombies an edge on
that the arguments expected declaration which starts with parsing.
are the arguments used, in extern is ignored. This is a
the correct order. They even convention that the zombies function pointers - Function
queue up return values that have adopted after watching pointers (anonymous or
can be returned from calls the way large legacy systems otherwise) are ugly. A
to the Mock, so that the test tend to throw extra extern’d typedef’d function pointer
writer can inject any values functions into their header files. is as easily dealt with as
desired. If you don’t agree, just change any other type... Function
:treat_externs from :exclude to pointers which appear inline
They do all this through :include. in the function declaration are
_Expect functions. One of typedef’d by CMock for easier
these Expect functions is anonymous arguments - C usage.
created for each Mock. An lets you specify a function
ExpectAndReturn is used if prototype without the variable void - Zombies treat ‘void’
the original function returned names, leaving only types. as something special, and
something, otherwise Expect CMock does its best to why shouldn’t they? A well-
is used. Later we’ll see how recognize these cases, but placed void is the difference
plugins will create additional can’t read minds. If you have between having arguments
functions. something like “unsigned or not. A void distinguishes
doohicky” it guesses that between functions which get
To deal with all sorts of code, doohicky is the name of Expect and those that get
from standard to proprietary, something of type “unsigned”. ExpectAndReturn. Some
from cutting-edge to legacy, It’s possible that’s not correct. odd systems out there
the CMock zombies make To help a little bit, the config actually typedef void, like
some assumptions. Let’s look arrays :attributes, :treat_as, ANTI_ZOMBIE_VOID. Tell the
at what these are. You can and the :unity_helper can zombies about these using
override many if you desire give CMock more information :treat_as_void, they’ll work
a different behavior (zombies about your types (see Captain through this subtle subterfuge
are weak-willed at best). Bacon’s Savory Sidebar). and get back to work.

< 20 >
debugging tests - more subtle problems. To
Sometimes it’s useful to make make this more convenient,
CMock complain more... The the generate_test_runner :cexception_include: ‘path\
option :memcmp_if_unknown script accepts a yaml section Exception.h’
can be set to false to make of :cmock: if it can’t find the :treat_as:
CMock complain whenever standard :unity: section, so :MY_INT: INT
it comes across an unknown you can just give it the same :MY_CHAR_STR: STRING
type (so you can add it to yaml file you’re using for :treat_as_void:
:treat_as or :unity_helper). cmock. - CUSTOM_VOID
The option :when_no_ :memcmp_if_unknown: false
prototypes can be changed build customization - You :when_no_prototypes: :error
from the default :warn to can control where your #opts :ignore, :warn, :error
:error to make CMock fail mocks get placed by setting :when_ptr: :compare_data
whenever you ask it to make :mock_path or even what #opts for last one
a Mock of a header where they are named by setting # :compare_ptr
no functions are detected (it :mock_prefix. These will # :compare_data
can also be set to :ignore for default to mocks\ and Mock # :compare_array
silence). respectively.

preprocessing - CMock Your very own sample yaml config:


knows a little about C, but
it’s not a compiler. If your :mock_path: ‘where\mocks\’
headers contain lots of :mock_prefix: mocked
preprocessor macros and :plugins:
#ifdefs, you might want to - :cexception
consider preprocessing your - :ignore
headers before giving them to - :callback
the zombies. :includes:
- mytypes.h
NOTE: It should be noted that - mydefs.h
:plugins and :enforce_strict_ :attributes:
ordering can (and should) - __irq
be passed to generate_test_ - __fiq
runner too. A mismatched :enforce_strict_ordering: true
set of options may lead to
compiler errors or (worse)

< 21 >
compile-time options

Zombies survive with a lot Don’t worry, you’ll get a CMOCK_MEM_PTR_AS_INT -


less brain cells than most of friendly failure with a clear Finally, CMock wants to treat
us... kinda like embedded message if the tests attempt your pointers as numerical
processors. Because of this, to pass this limit. types sometimes... and it
you sometimes may want to needs to make sure it’s got
control how they deal with Many targets get picky about a big enough int to handle
that limited memory. There where you access data. You that. On many machines,
are some #defines you can should probably tell CMock that’s an unsigned int... but
make (as command line about that. You can do that sometimes (we’re looking at
options to your compiler, by setting CMOCK_MEM_ you 64-bit machines), it might
most often) to help: ALIGN. Check out this handy be something else.
chart:
You can specify if CMock has
a fixed amount of memory 0 - Don’t align (or align to byte)
to work with or if it should 1 - Align to 16-bit word
pull memory from the heap 2 - Align to 32-bit word
by defining CMOCK_MEM_ 3 - Align to 64-bit word
STATIC or CMOCK_MEM_
DYNAMIC. By default, you CMOCK_MEM_INDEX_TYPE
get a static block of 32kb. - Internally, CMock has some
accounting to do. This is
Then, specify CMOCK_MEM_ the type it should use an an
SIZE. If you’re working with index. Usually it’s set to be
dynamic memory, this is the an unsigned int... but you can
size of a chunk you allocate make it something smaller
each time you need to “dip in if you’re working with little
for more.” A larger number memory.
makes for higher performance.
This number is the total
amount of memory CMock
will use if you’re using static
memory.

< 22 >
Thunder Duck touches down “Ha!” says Thunder Duck, “No sir, if he had a type PIG_T,
lightly on the top of the building, unphased, “He’ll be wasting he would just need to have
his bill grim. He presses his all his time trying to figure out a macro defined for UNITY_
code-breaking box to the which element was actually TEST_ASSERT_EQUAL_PIG_T,
stairwell door and waits a wrong.” taking four arguments... the
moment. It beeps and the door expected value, the actual
clicks open. Inside he finds “True... unless...” value, the line number (for
rows and rows of servers. He printing) and an error message.”
crimps into one of the lines, “Unless, what? Spit it out,
then plugs it into his wrist Bacon... I need to know what “And CMock will scan that, and
computer... a moment later, it I’m up against!” automatically match the types?”
begins to spit out data.
“Sir, he can add his own “Yes sir.”
“Captain Bacon... he’s definitely assertions to unity helper
Mocking... But there’s no way files. As long as he follows Thunder Duck sighs, “So what
he can stick with standard the naming convention, about arrays, Bacon? How
types forever! When he needs CMock can find them in the does it know what he wants?
to pass structs or arrays as specified helper file and it will What if it’s a null pointer...
arguments, his evil plans will be automatically use any types or just a pointer to a single
thwarted!” that it recognizes.” structure?”

“No sir... CMock can handle “Blast! Surely that must be “Pointer treatment is configured
any type you want. If it doesn’t incredibly difficult!” by setting :when_ptr. If set
know the type, it’ll perform a to :compare_ptr then only the
simple memory comparison.” pointers address is compared.”

< 23 >
“But the default configuration Bacon sends an example C A P T A I N
is :compare_data. With this to Thunder Duck’s high-tech B A C O N ’ s
setting, if the pointer that wristwatch, who scans the S A V O R Y
you Expect is a NULL, it’ll source code, noticing the S I D E B A R
verify that the actual pointer BACON_T and FOOD_T types. Just like Captain Bacon, you can
is also NULL. If it’s actually add your own custom types. When
pointing to something, then a “And those,” Thunder Duck faced with non-standard types,
single element comparison is asks slowly, almost afraid to you have options. Try all three!
performed by default.” finish his question, “Those are
more custom types that are 0. Do Nothing
“Excellent! Just the first element automatically discovered in the CMock will perform a memory
isn’t enough to cover all cases!” Unity Helper?” compare and report mismatches.
The negative: No details.
“Unless he enables the :arrays “Yes sir,” Captain Bacon says,
plugin. If he does that, every grimly, “Yes.” 1. Pseudo Standard Type
mocked function gets its usual typedef int FUNKY_NUM;
Expect function... plus a new Thunder Duck swallows. He typedef char* SILLY_STR;
ExpectWithArray function. For needs to take action soon! typedef unsigned char* Meh;
each pointer argument passed Dr. Surly can’t be allowed to Just specify how you want them
to that function, there are now continue with these plans. treated in your YAML file. Choose
two arguments. The first is a INT, HEX8, HEX16, HEX32, or
pointer to the expected data, Bonus! Try setting to :smart to STRING:
and the second is the number have it act like :compare_ptr :treat_as:
of elements to check.” when you specify 0 elements, FUNKY_NUM: INT
or :compare_data otherwise! SILLY_STR: STRING
Meh: HEX8*
void AddBacon(BACON_T* SomeBacon);
void AddBaconToAll(BACON_T* SomeBacon, FOOD_T* Foods); 2. Your Own Swank Types
We could define a macro in a
will be Mocked with the following ExpectWithArray functions: helper function like MyHelper.c for
the new type like UNITY_TEST_
void AddBacon_ExpectWithArray(BACON_T* SomeBacon, ASSERT_EQUAL_WACKY_T, then
unsigned int SomeBaconDepth); add the path in our YAML file:
void AddBaconToAll_ExpectWithArray(BACON_T* SomeBacon, :unity_helper: tst\
unsigned int SomeBaconDepth, MyHelper.c
FOOD_T* Foods, unsigned int FoodsDepth);

< 24 >
We find Dr. Surly still working in his lab... a look of elation on his face. A look of elation brought
on by simultaneous discovery and security. He has just discovered the option to enforce strict
ordering... an option which makes him feel much safer. Instead of just enforcing the order of
arguments to a specific function call, it enforces the order of all function calls made.

:enforce_strict_ordering: true

When Dr. Surly wants to use his Energy Ray, he knows he needs to charge the system three
times, each time passing the number of charges remaining. Only then can he fire the Ray. He
would obviously set up his test like so:

void test_EnergyRay_Fire_ShouldChargeThreeTimesThenFire(void)
{
EnergyRayHardware_LoadCharge_Expect(2);
EnergyRayHardware_LoadCharge_Expect(1);
EnergyRayHardware_LoadCharge_Expect(0);
EnergyRayHardware_Fire_Expect();

EnergyRay_Fire();
}

CMock always catches problems like the one below. It always remembers the order of
parameters passed to a single expect (notice we’re counting in the wrong direction):

void EnergyRay_Fire(void)
{
int i;
for (i = 0; i < 3; i++)
EnergyRayHardware_LoadCharge(i);
EnergyRayHardware_Fire();
}

But if this option were disabled, there is a potential error he could make that would go uncaught.
He feels safer knowing that he has protected himself from this possibility. The key is that Dr.
Surly knows that he needs to charge before he has enough energy to fire.

< 25 >
void EnergyRay_Fire(void)
{
int i;
EnergyRayHardware_Fire();
for (i = 2; i >= 0; i--)
EnergyRayHardware_LoadCharge(i);
}

He understands that some people want to turn off the global-order-enforce option to make test-
writing simpler, but he’s not interested in simplicity. He’s interested in correctness. That’s why
he’s testing in the first place! As soon as he has enabled :enforce_strict_ordering, problems like
this are obvious.

Captain Bacon! “Now, I’m working on an App


for our hero-phones to make void test_Phones_Should_
them vibrate in the correct VibrateInSequence(void)
order to specify when each {
of us should move... so we Smoke_Reload_Expect();
all arrive in Surly’s lab at the Smoke_Reload_Expect();
same time.” Vibrate_Expect(Duck);
Smoke_Reload_Expect();
“I’ve been using this CMock “Fabulous,” says Bacon. Vibrate_Expect(Bacon);
thing while planning our Smoke_Reload_Expect();
raid on Dr. Surly’s lab. I’ve “Fabulous,” agrees Gobbler. Vibrate_Expect(MrGuy);
developed a series of smoke Smoke_Reload_Expect();
machines which are going “But there’s a problem.” Smoke_Reload_Expect();
to fill the area with smoke Vibrate_Expect(DimBulb);
so that we can arrive under “Sir?”
cover.” CoordinatePhones();
“The function which }
“A genius plan,” says Captain coordinates phone vibration
Bacon. timing also reloads each “Maybe that’s an indicator that
smoke machine.... can I just you should refactor that into
“Yes, genius,” agrees The specify vibrate calls without two functions.”
Gobbler. all the reload calls?” the Duck
asks, showing them his code.

< 26 >
“Let’s say that’s not possible,” he growls.

“No problem, sir,” the pig replies, typing at the terminal, “Just enable the :ignore plugin, then
tweak your test to look like this.”

void test_Phones_Should_VibrateCorrectSequence(void)
{
Smoke_Reload_Ignore();
Vibrate_Expect(ThunderDuck);
Vibrate_Expect(CaptainBacon);
Vibrate_Expect(MrToughGuy);
Vibrate_Expect(TheDimBulb);

CoordinatePhones();
}

“Nice... so what if Smoke_Reload has a return value?” asks the duck.

“No problem sir, you can use IgnoreAndReturn and specify just the return value, like this.”

void test_Phones_Should_VibrateCorrectSequence(void)
{
Smoke_Reload_IgnoreAndReturn(100);
Smoke_Reload_IgnoreAndReturn(80);
Vibrate_Expect(ThunderDuck);
Vibrate_Expect(CaptainBacon);
Vibrate_Expect(MrToughGuy);
Vibrate_Expect(TheDimBulb);

CoordinatePhones();
}

“Here,” explains Captain Bacon, “We’re telling our test to return 100 the first time Smoke_Reload
is called, then 80 every other time. We could have just specified a single value to always be
returned, or could specify all the returns values expected... while still ignoring the arguments
passed to the function.”

< 27 >
As Dr. Surly begins to think C “This explains why the arrows
about his next feature, the point out from Conductor.
Clashing Tentacles with M H Only the Conductor knows
Chaotic Tendencies, he about the other parts of the
realizes that this module will module.”
be significantly larger than C
those he has developed Dr. Surly grabs the paper
previously. Thinking about M H from Sourpuss and stares
testing such a big module at it, “I see, I see... so the
seems daunting. Conductors might all get
“Oh! Design Patterns! I’ve called from the main loop...
“It’s too big! Too complex!” he seen some of these before.” they conduct the interaction
yells, his frustration seething between the Models and the
in his voice. He throws his “OK, First MCH. Three .c Hardware... and Modules
head on the table. files? Well, yes, I suppose a talk through their Models
module isn’t necessarily one only, right? Very eloquent,
file... but it’s just so... er... uh.” Sourpuss... I must say.”

“Why three files?” “What happens if I were to


use an OS? Ah! Of course...
“Model, Conductor, Hardware. Each Conductor becomes a
Yes, I see Sourpuss... All the task. Very nice, Sourpuss....
A calm hand wrests on hardware interface happens in when do we use this?”
his shoulder... or... a paw. the Hardware file. The Model
Looking back, he finds is the module’s only link to the
himself staring at the serene outside world, and contains MCH periodic background tasks and
face of Sourpuss, whose all private state and data. The places where you don’t need
rarely-open eyes exhibit a Conductor just coordinates to wait for results
calming effect. them. Ideally the Coordinator
reads like simple instructions, D(I)H event driven features and
Sourpuss steps around him like: places where we expect a
slowly and gingerly takes response in a timely manner.
the pencil. He draws in if (Model_IsReady( ))
slow precise strokes in the Hardware_SendPacket W when we just want to
air. Surly watches over his if (Hardware_Triggered( )) specialize an existing
shoulder. Model_TellSomeone interface

< 28 >
“Yes, I see that’s a nice chart,” any data or event flags that need
says Dr. Surly, “but what are to be stored are performed in a I
these other patterns that you callback function in the Driver.
have listed? The Driver sets up the callback D H
during initialization.”
“I see, D(I)H is Driver Interrupt
Hardware, and the Interrupt is “You don’t need to explain this
an optional aspect. The main last one, Sourpuss,” says
interface and state are stored in Dr. Surly, “I can guess that a D H
the Driver, much like the Model Wrapper is just a thin abstraction
of MCH. Unlike a Model, though, around an existing module...
this directly calls Hardware. like if we want to coordinate a
If there is an interrupt, the couple of GPIO pins to control
hardware portion of the handler motor speed, the MotorSpeed W M
is in Hardware as expected, then module is likely to just be a
wrapper around GPIODriver.”

SOURPUSS SLOTH’S SANGUINE SIDEBAR


There are five thousand seven hundred and twenty one design patterns that can
be applied to any good embedded application. I know... I painstakingly counted
them last Thursday. You could (and most embedded developers do) ignore the
world of design patterns completely and design from your own experience and
instincts. There might be patterns in there... but you don’t care what they are.
So why are we spending two precious pages on this? Two reasons, really.
1 - These patterns have proven to be useful for keeping complexity down and for
making our software easily testable.
2 - They’re good examples of how you shouldn’t be afraid to break things into
smaller pieces if it means you can test it easier.
What if you wanted to use these patterns, but you have modules that sometimes are waited
on and sometimes are polled. Our experience has shown a general rule can help here too.
Occam’s razor says the simplest answer is usually correct. When you are using an RTOS, the
simplest answer is to use MCH (Conductors make such nice tasks). When you’re doing the
classic ‘super-loop’ application, DH is simpler because you would otherwise need to kick
that Conductor periodically to keep it cranking away. That would be yucky. If you’re using
coroutines... well... you’re on your own. We haven’t tried a coroutine application since we
learned the rest of this crazy testing stuff.

< 29 >
His last feature, the Clashing Tentacles with Chaotic Tendencies, will flail around wildly,
smacking and bludgeoning everything they touch. When one of them manages to grab
something, it will pick it up and throw it as far as possible. Anxious to get going, Dr. Surly
generates the source module as an MCH triad and digs in.

> generate_source_module -pMCH Tentacle

If Dr. Surly understood Sourpuss’s description of the MCH pattern correctly, he believes that
starting with the Conductor makes the most sense. He opens TestTentacleConductor.c and
enters his first test:

#include “MockTentacleModel.h”
#include “MockTentacleHardware.h”
#include “TentacleConductor.h”

void test_TentacleConductor_Exec_ShouldFlailWildlyWhenFree(void)
{
TentacleModel_HasSomething_ExpectAndReturn(FALSE);
TentacleHardware_FlailWildly_Expect();

TentacleConductor_Exec( );
}

That looks pretty good. It asks the Model if anything has been captured. This test injects a
FALSE as the answer to this query, so the Hardware should then be instructed to flail wildly. If
that doesn’t happen, it’ll fail the Expect calls.

He adds declarations for TentacleModel_HasSomething and TentacleHardare_FlailWildly


to TentacleModel.h and TentacleHardware.h, respectively. Then, he adds a declaration for
TentacleConductor_Exec as well as an empty implementation. Running the test, it fails as
expected. He then updates the Conductor.

void TentacleConductor_Exec(void)
{
if (!TentacleModel_HasSomething())
TentacleHardware_FlailWidly();
}
< 30 >
The test passes. He now has a choice. Will he continue to implement TentacleConductor, or
start filling out details of the Model or Hardware? Whichever he chooses, how does he keep
track of what he needs to do? As the panic begins to arise, he is reminded of a unity feature:
TEST_IGNORE. He quickly adds a test to the Model and Hardware containing a line like this:

TEST_IGNORE_MESSAGE(“Don’t forget TentacleModel_HasSomething”);

These ignore messages will show up in the test report but won’t count as failures. That should
remind him what needs to be done... kinda like leaving a trail of breadcrumbs. So, breadcrumbs
in place, he adds another test to the Conductor.

void test_TentacleConductor_Exec_ShouldThrowStuffItCaught(void)
{
TentacleModel_HasSomething_ExpectAndReturn(TRUE);
TentacleHardware_ThrowIt_Expect();

TentacleConductor_Exec( );
}

This, of course, fails. He updates the source to make it pass:

void TentacleConductor_Exec(void)
{
if (TentacleModel_HasSomething())
TentacleHardware_ThrowIt();
else
TentacleHardware_FlailWidly();
}

Happy with the Conductor for now, Surly moves on to the Model. He figures that he’ll have a
new module called Grip, which will detect if something is in the tentacle, so the TentacleModel
can call that. The Grip check is pretty fast and can be performed on demand, so he decides it’ll
be a Driver-Hardware module. First he creates the new modules:

> generate_source_module -pDH Grip

< 31 >
Then he adds the first test to TestTentacleModel.c

#include “MockGripDriver.h”
#include “TentacleModel.h”
void test_TentacleModel_HasSomething_ShouldCheckGrip(void)
{
GripDriver_HasSomething_ExpectAndReturn(TRUE);
TEST_ASSERT_TRUE(TentacleModel_HasSomething());

GripDriver_HasSomething_ExpectAndReturn(FALSE);
TEST_ASSERT_FALSE(TentacleModel_HasSomething());

GripDriver_HasSomething_ExpectAndReturn(TRUE);
TEST_ASSERT_TRUE(TentacleModel_HasSomething());
}

He adds a prototype for GripDriver_HasSomething, adds a TEST_IGNORE for it, and adds the
empty TentacleModel_HasSomething (is this getting automatic yet?). Run and fail. Implement
and refactor (if needed). It’s this pattern over and over again.

Dr. Surly is so engrossed in his work, that he almost doesn’t notice when his proximity alarm
begins to blink. When it finally catches his attention, he yells to Sourpuss, “We’ll have to release
with the last version! No time to finish the tentacles... let’s crank this thing onto the roof!”

Sourpuss leans over and presses “Deploy” on their continuous integration server. One of the
advantages of working this way is that you should have a fully tested system almost every
time you commit... so doing a quick release (especially when being invaded by superheroes)
shouldn’t be too much of a problem.

As the server hums, Dr. Surly opens another window and attaches to his security cameras. He
finds Thunder Duck and his meddling sidekicks near the back door. He should have known it
would be them! No matter... his dastardly plans have evolved far enough. It is time.

< 32 >
Meanwhile,
The Quack Crusader Bacon, what is that thing?
and his allies arrive just
outside Dr. Surly’s lab... It appears to be a
Catch block... Dr.
Surly must be using
an exception handling
library for C, like
CException!

Catc
h(e
Hand ) {
} leEx
ce ptio
n(e)
;
“What does it do?” asks the AFunction(); “This is stack manipulation
duck. ThisFuncHasError(); kinda stuff... there is no way
ThisFuncNotCalled(); he could be testing that
“It’s for error handling. Instead } properly. Let’s go in there
of returning error codes from Catch(e) { and get him!”
every function or other messy //RespondToErrorHere Everyone ready?
ways of handling errors, //e has thrown id
CException allows control to }
be transferred directly from a }
Throw call to the most recent
Catch, where the error can be “How does that work?” he
cleaned up as desired.” asks.

void ThisFuncHasError() “It uses the standard


{ Throw(0x53); } library setjmp and longjmp
functions,” says Captain
void SomeFunc(void) Bacon. Ready, sir...
{ Did you hear something
Try { “This is great!” exclaims that sounded like the
//Any problems here Thunder Duck. ThunderMobile?
//get caught below

< 33 >
Halt Dr. Surly! We’re on to
your plan!
I Muwa hahahahahahaha!
Too late, Quack! It’s all Of course it’s tested! There is
released! a CMock plugin to support
CException!

But it’s buggy, Surly!


We know you were using
CException. That untested
code will be your undoing!

“It’s simple to verify that a function throws “... and,” continues Dr. Surly, “It’s easy to verify
when expected,” says Dr. Surly, “Just wrap it a function catches an error. The :cexception
in a Try block in your test, fail if an error wasn’t plugin adds ExpectAndThrow functions which
thrown or if it’s the wrong error.” can for a called function to throw an error at
any desired time.”
void test_VerifyThrow(void)
{ void test_VerifyCatch(void)
CEXCEPTION_T e; {
Try CEXCEPTION_T e = 5;
{
FunctionToTest(); SubFunc_Expect(22);
TEST_FAIL_MESSAGE( SubFunc2_Expect(33);
“no throw!”); SubFunc2_ExpectAndThrow(44, e);
}
Catch(e) //Test Runner will catch
{ //if uncaught here and will
TEST_ASSERT_EQUAL(2,e); //cause test failure
} FunctionToTest();
} }

< 34 >
Muhahahahah! You can’t stop me!
Captain Bacon, My VR Goggles,
I’m gonna find a bug!

Dr. Surly throws the switch. His masterful invention lumbers to life with an ominous hum. Thunder Duck
knows his only option is to dive into the chaotic world of embedded software and find a bug... any loophole
which he can exploit to intercept Dr. Surly’s dastardly plans. But he’s up against an evil genius, a sloth, and
a pair of open source test tools. Can he prevail?

< 35 >
Let’s start with main( ), Surly. Did you
skip it because the test runner already
defines a main?

Ha! It’s easy to test,


with just a little preprocessor goodness!

#ifdef TEST
#define MAIN app_main
#else
#define MAIN main
#end

int MAIN(void){...}

“It’s a common convention to “Let’s say you have a private “Doesn’t that make your tests
define TEST when compiling function in your C file by more brittle?”
tests and not defining it when declaring it static. If you just
building a release. While declare it STATIC instead, “A little,” Dr Surly admits, “The
we want our main source to and use our new TEST friend tests are more closely linked
contain as little code related to define STATIC to static to your implementation. It’s a
to testing as possible, there during releases but nothing tradeoff, for sure.”
are instances such as in main otherwise, we have an easy
where a little hack is really way to make private functions
useful.” visible during tests. This
can allow us to provide more
“Like what else?” Thunderduck rigorous tests on the guts of a
asks, momentarily distracted. module if we desire.”

< 36 >
“So what about an infinite “Nonsense,” Dr. Surly states, “use a slightly more verbose
loop?” Thunder Duck “Instead of using the usual method...”
challenges, “Embedded options like these:”
systems often have infinite do {...}
loops. As soon as you call that while(1) { ... } while(FOREVER);
function in a test, it’ll execute for(;;) { ... }
forever and you’ll never get “...where FOREVER is defined
results!” to be 1 during a release build
but 0 during a test. This will
make the loop execute only
What about function pointers, Dr Surly? I see you have once.”
an array of function pointers and you use a message id to
determine which function gets called. I bet that thing’s not
well tested!

You’d bet wrong, Thunder Duck! I


can use expects as usual. Just
include the mock for each function
handler. I just give each one a test
like this one:

test_func3ForId3(void)
{
GetId_ExpectAndReturn(3);
Func3_Expect();

Dispatch();
}

< 37 >
But you likely missed one...
especially if you added
handlers over time!

No way, Thunder Duck.


For situations like this, like enums
that change behavior or lists of handlers
changing over the life of the project, I add a
reminder test. It’s triggered off the current
enum or array size and will fail when those
change, reminding me to add more unit
tests for the new cases:

test_AllHandlersChecked(void)
{
TEST_ASSERT_EQUAL(7,
(sizeof(Handlers[]) /
sizeof(HANDLER_T)));
} “True.”
A well named test or a comment to
explain the failure finishes the task. “Ah!” Thunder Duck exclaims,
“This is the one! You cannot
possibly use your tools in such
“Ok, Surly,” Thunder Duck “Even assuming that the guts a situation! You’ll be stuck for
smirks, “Let’s say you have a of this system work properly, sure!”
large body of existing code... how do you use your precious
maybe an RTOS, a library, or a mocks? This thing could be a “It’s fine,” the mad scientist
block of re-used legacy code... huge collection of header files, a assures him, “It just takes a little
Surely you’re not going to test maze of #ifdefs and #ifndefs, or bit of work. Instead of linking
it all.” might even include conflicting to all of those files, you want to
declarations depending on create a single header which is
“Not likely,” he admits. which files you link to!” the API you’re using.”

< 38 >
“Huh?” single header called something mock and use in any tests that
like FreeRTOS.h or maybe make OS calls,” Dr. Surly says
“Let’s say you’re going to use OS_API.h. In this file, you put with a satisfied smile.
FreeRTOS, a decent open function prototypes for all the
source real-time operating functions that you are using in “I suppose you’d just include the
system. Instead of including the OS. This is creating a great types too?”
a header file for queues, reference (documentation!) for
mutexes, semaphores, tasks, how you are using the RTOS, as “Most likely.”
and whatnot, you create a well as a single file that you can

oh! He’ll disconnect Thunder Duck’s


macros! connection!
Look out,
Captain Bacon!
The Sloth!

Never Fear! No One Can Resisit The Smell Of Bacon!

Uh... sloths are


herbivores...

Macros are ok too.


I use #ifdef TEST in
the header file to
create a mockable
function prototype
instead of the macro
for tests only.
...but luckily lazy.

< 39 >
“Wait a minute!” says Thunder Duck, “So you are saying you “Hurumph,” Thunderduck
would take macro and function definitions that are meant to be grumbles, searching through
public, and collect them all in one header like this?” more lines of code, “Ah! What
about this place where you use
int OS_TaskDef(FUNC*, int); the ignore plugin!? It looks like
int OS_SemaSet(int); you needed to know how many
int OS_SemaWait(int, int); times the function was called,
but just didn’t care about the
//Note: declared as macros elsewhere during release. actual arguments? But the
#ifdef TEST ignore plugin doesn’t work that
int OS_Mutex_Enter(int); way!”
int OS_Mutex_Exit(int);
#endif “True, the ignore plugin defaults
to behaving as if :ignore has
//Note: defined here for convenience during release been set to :args_and_calls...
#ifdef TEST switching to :args_only will
int OS_SemaSetFromISR(int); change the behavior of that
#else plugin and make it care about
#define OS_SemaSetFromISR(a) \ how often functions are called,
{ OS_SemaphoreSet(a); SWI; } just like an _Expect, but not care
#endif about the actual arguments. In
either case, the return values are
“Yes,” Dr. Surly agrees, “That really bad... but honestly the handled the same.”
is exactly what I mean.” manual method is usually not
as bad as it seems.” “What if you’re checking an
“I am sure that could get argument’s pointer address
tedious if the library you’re “So that just leaves testing the instead of the value?”
talking about has a lot of library itself?”
custom types or conditionals,” “I always have CMock in :smart
insists Thunder Duck. “Sure, but most people will pointer mode... I’m checking
just write tests to verify their for NULL or dereferencing my
“Yes, it could,” Dr. Surly assumptions about the API pointers to check their contents.
says, “But you could always of the library or a few simple Otherwise I suppose you could
choose to run the library code tests... you leave the thorough use that TEST define again to
through a preprocessor to testing to the library provider make those local variables public
generate that header if it was or it’s long track record.” during a test,” Dr. Surly muses.

< 40 >
“Explain,” Thunder Duck growls, not liking the sound of this plugin.
#ifdef TEST
int Num; “Let’s say you have a function like this, which you knew would
#endif update val then return a status code.”
void FuncToBeTested(void)
{ int DoSomething(short* val);
#ifndef TEST
int Num; “Instead of calling your _Expect’s, you will call DoSomething_
#endif StubWithCallback once at the beginning of the test. You’re mostly
... telling CMock that you have special handling for this function and
} that it should call your custom written stub function instead of
doing the normal mock stuff. The stub has the same argument
“I know!” Thunder Duck says, and return types as the function being stubbed.”
“Side effects! In C, people
will often pass a pointer to “There are a couple of options that are important here. First, you
a buffer that they expect to can leave :callback_after_arg_check as false to just call your
be filled by a function... or a callback function, or true to check the arguments as an expect
pointer to some other type, would before calling your callback function.”
but they expect the function
being called to modify it in “There is also :callback_include_count which will add an additional
some way. How do you go argument to your callback function which is an integer containing
about mocking something like the number of times the callback has been fired. This option is
that? In all your work so far, I set to true by default.”
have seen arguments checked
for expected values, but only “Let’s say I’ve gone with the default options and each time I
the return value is actually want the number argument to be set to the number of times the
updated.” function has been called times the incoming value. Also, let’s say
we want to make sure our callback is only called twice.”
“For that,” Dr. Surly says,
smiling mischievously, “You int MyDoSomethingStub(short* val,int NumCalls) {
need another of CMock’s *val = val * NumCalls;
plugins. Just turn on the if (NumCalls >= 2)
:callback plugin and you TEST_FAIL(“called too many times”);
suddenly have a lot of power return 0;
in how you can customize your }
tests.”

< 41 >
void test_DoSomething_shouldActuallyDoIt(void) { “Yes... I wanted to test using
DoSomething_StubWithCallback(MyDoSomethingStub); the same compiler that my
AnotherFunction_Expect(45); release was built with,” Dr.
YetMore_ExpectAndReturn(5); Surly says proudly.

//This calls DoSomething “This is your linker file?”


DoSomethingCaller(45, 3); Thunder Duck asks,
} referencing a linker file that
had been thrown together
“This seems much more complicated than the expects and quickly for tests. Like most
ignores,” Thunder Duck laughs. test linker files, it was quick
and dirty... lots of extra
“True,” Dr Surly says, “But the callback plugin gives you some memory for the tests... no real
real power. You can use it to perform complex calculations organization. Usually that’s
based on incoming data, to fill buffers or other things passed fine.
by reference, or even to write your own fancy expect calls
which check only certain arguments. You’re in full control of “Yes,” Dr. Surly says, pausing.
how the mocked out function will behave, a trade of power for Something seems amiss.
complexity.”
The Duck smiles triumphantly,
“Couldn’t you accomplish the same thing by just writing a test “One of your test strings could
stub for all your functions on your own?” get linked to start at address
zero! You’re not doing
“Of course you could, but this is the best of both worlds... The anything to map where any of
stub interfaces are generated in addition to the Expect calls the code or data goes... and
and whatever other plugins you have enabled. You can use if it DOES get linked to zero,
automatically generated mocks most of the time, and just use any pointers to it are going to
the complicated version when absolutely necessary.” get interpreted as NULLS!”

Thunder Duck scowls and resumes his search through “That seems highly unlikely,”
Surly’s code. Somewhere in here there must be a problem... Dr. Surly says, but he’s paled
something that cannot be caught! slightly... or he would be more
pale if he wasn’t so pasty
Then he sees it. A slow smile grows across his face. white from all those years
“You’re testing in a simulator, right Surly?” indoors.

< 42 >
“Unlikely or not... it’s possible!” Thunder Duck thunders. He scans through all the test cases quickly in
search of a test that might have this fault. He feels anxious. The likelihood of this bug occurring is slim...
but the linker file wasn’t set up to avoid such a mistake. It is possible!

But before Thunderduck can declare victory over his foe, Dr. Surly vanishes!

WHAT!? Where did he just go?

He Threw himself like a CException, sir!


Remember when we saw that Try... Catch outside? He just
threw himself back to that Catch!

“The one page 33?” Thunder And so we must now leave


Duck demands, “When you the Billed Crusader, The
asked if I thought I heard the Mad Scientist, and the
Thunder Mobile?” other misfits that fill these
pages. While there are likely
“Yes,” squeaks the pig. many unanswered questions
remaining, that’s what forums
As the realization settles in of and sequels are for.
just WHO stole the Thunder
Mobile, Thunder Duck is filled For now... don’t you have
with a rage! some code of your own that
you should be writing?

< 43 >
void SetOrange(ORNG p)
int SetApple(APPLE P)
... automatically get Expects like
SetOrange_Expect(ORNG p)
SetApple_ExpectAndReturn(
APPLE P, int toReturn)
... plus these with Ignore plugin:
Unity Asserts - Pag
SetOrange_Ignore(void) Unity Options - Pag e 8
CMock Options - Pag es 9-10
SetApple_IgnoreAndReturn(
Expects - Pages 16- es 19-22
int toReturn) Ignores - Pages 26-18
27
Callbacks - Pages 41-
.... plus with cexception plugin: 42
Arrays - Page 24
SetOrange_ExpectAndThrow( CException - Page 33-
34
ORNG p, EXCEPTION_T e)
SetApple_ExpectAndThrow(
APPLE P, EXCEPTION_T e)
... plus with Callback plugin:
SetOrange_StubWithCallback(
CMOCK_SetOrange_CALLBACK c)

erfile)
le (runn
y m l) (o p ts) testfi
onfig. rom.
nner.rb (c runner f
n e ra te _ test_ru
fi le to create a nner.
ge test a ru
h of the cify the path to l file, or
- the pat pe n of a yamort happens
testfile le - optionally s s e c ti o
:cmock: of CMock sup
p
runnerfi nity: or n
p e c ifi ed in a :ue. The inclusioader.
can be s and lin the he cmock
options from the comm are included in rd e ri n g enabled in
directly ically if mocks trict o
u have s
automat u s e when yo es to use on LL
orde r - inclu d :cexcepti before/after A
_strict_ ditional e using d
:enforce - a list of adit cares if you’rde to be inserte
:includes- in particular _teardown - co
:plugins etup and :suite
:suite_s

< 44 >

S-ar putea să vă placă și