Transcript
How to Use Ceedling for Embedded Test-Driven Development with Step-by-Step Examples Matt Chernosky http://electronvector.com
Copyright © 2!" Matt Chernosky. #ll rights reser ve$.
Contents %elcome..........................................................................................................................................................................& %hat is 'est-(riven (evelopment )'((*+.........................................................................................................., 'he 'ools.......................................................................................................................................................................... nstalling Cee$ling......................................................................................................................................................." Creating a ew Cee$ling 0ro1ect........................................................................................................................... Example 3!: Starting '(( with Cee$ling............................................................................................................4 Create a Mo$5le......................................................................................................................................................4 mplement a 6eat5re...........................................................................................................................................!! 7epeat.......................................................................................................................................................................!& 7e8actoring..............................................................................................................................................................! Mocking 9ar$ware nter8aces...............................................................................................................................! Example 32: Mocking a 9ar$ware nter8ace with CMock..........................................................................!4 Create the 'emperat5re Sensor Mo$5le.....................................................................................................!4 %rite 5r 6irst 'est..............................................................................................................................................!4 Create the 65nction ;n$er 'est......................................................................................................................2! Mock the 2C nter8ace.......................................................................................................................................2! mplement the 65nction ;n$er 'est.............................................................................................................22 #$$ing #nother 'est...........................................................................................................................................22 7e8erences....................................................................................................................................................................2, So5rce Co$e...........................................................................................................................................................2, (oc5mentation.....................................................................................................................................................2, Cee$ling <5ick 7e8erence......................................................................................................................................2 'est #ssertions.......................................................................................................................................................2 Mock 65nction 6ormats.....................................................................................................................................2"
How to Use Ceedling for Embedded Test-Driven Test-Driven Development
2
Welcome Maybe yo5=ve hear$ o8 Test-Driven Development )'((*> an$ maybe yo5=ve even tho5ght it seeme$ like a reasonable i$ea. If you havent tried TDD yet though! you really should" 'his g5i$e contains step-by-step examples to get yo5 starte$ test $riving in C> especially 8or embe$$e$ so8tware applications. %e=ll look at how to 5se the 5nit test 8ramework calle$ Cee$ling to help 5s $o this. n the 8irst example> we=ll see how to create tests an$ write the co$e to make them pass. n the secon$ example we look at mocking> an$ learn how to 5se it sim5late o5r har$ware. #ll the tests in these examples compile an$ r5n on yo5r host 0C )with ?CC*> with no target har$ware nee$e$.
How to Use Ceedling for Embedded Test-Driven Development
&
What is Test-Driven Development #TDD$% 'he premise o8 '(( is that we 5se the creation o8 5nit tests to incrementally $rive the $evelopment o8 the so8tware. 'he steps look like: !. %rite a test> an$ watch it 8ail. 2. mplement 15st eno5gh co$e to make the test pass. &. 7e8actor. ,. 7epeat. 'his allows 5s to be very clear abo5t what the co$e is to $o> beca5se we=ve $e8ine$ every behavior in a test. %ith each iteration yo5 a$$ a bit more 85nctionality to yo5r so8tware> an$ the tests give yo5 con8i$ence that yo5=re $oing it correctly. ne o8 the $i88ic5lties o8 5nit testing is that it takes some $egree o8 experience to write testable co$e. 8 yo5 write the tests 8irst tho5gh> yo5=ll 8ig5re o5t how to make yo5r co$e testable while yo5 write it. 'his means yo5 won=t waste yo5r time with this problem at all@ 6or me> the greatest aspect o8 '(( is that it takes a big problem to solve )how to implement a so8tware application* an$ re$5ces it to a simple problem )what is the next little thing nee$ this so8tware to $o*. 'hen 15st write a test 8or that 8eat5re> implement it an$ repeat. Ao5 simply stop when yo5 $on=t nee$ any more 8eat5res. #n$ when yo5 $o stop> yo5=re con8i$ent that what yo5 have is working exactly how yo5 want it to. t=s 5nlikely that yo5=ll be spen$ing a lot o8 time chasing $own b5gs.
How to Use Ceedling for Embedded Test-Driven Development
,
The Tools 'he testing tools 5se$ in this example are Cee$ling> ;nity an$ CMock. 'hese are the best C 5nit test tools available> 8rom the people over at http://www.throwtheswitch.org/ . Cee$ling is an a5tomate$ testing 8ramework 8or C applications. t=s b5ilt aro5n$ 7ake> which is the 75by programming lang5age=s b5il$ tool. 'hat=s why all o8 the BCee$ling comman$s are act5ally 7ake comman$s. n or$er to $o '((> yo5 nee$ to be able to create an$ r5n tests easily since yo5=ll be $oing it all the time. Cee$ling provi$es a5tomatic test $iscovery> mock generation an$ test exec5tion> which makes it the best option 8or 5nit testing in C. t also b5il$s an$ r5ns tests on the host 0C> so when working on an embe$$e$ pro1ect we $on=t have to waste time $ownloa$ing to the target. ;nity is the 5nit test 8ramework provi$e$ with Cee$ling. t gives 5s all o8 o5r test assertions constr5cting o5r tests. CMock is the mocking 8ramework 5se$ with Cee$ling. 'he mocking 8ramework is what lets 5s sim5late interactions with other so8tware mo$5les> so that we can test o5r so8tware 5nits in isolation.
How to Use Ceedling for Embedded Test-Driven Development
Installing Ceedling Cee$ling reD5ires 75by to r5n an$ 5ses ?CC to b5il$ each test. !. nstall 75by %in$ows installer: https://$l.bintray.com/oneclick/r5byinstaller/r5byinstaller-2.&.!.exe ther instr5ctions: https://www.r5by-lang.org/en/$oc5mentation/installation/ . &e sure that the 'uby bin folder is in your path> e.g. C:75by2&bin 2. nstall Cee$ling with the 75by FgemF tool with the comman$: gem install ceedling Installation Error: “certificate verify failed” I’ve recently had an issue trying to use the gem! command" It’s a problem with the #uby$ems server %where Ceedling and other gems are hosted&" If you get an error li'e this( ERROR: Could not find a valid gem 'ceedling' (>= 0), here is wh: !na"le to download data from htt#s:$$ru"gems%org$ & connect returned=* errno=0 state=v+ read server certificate : certificate verif failed ( https://api.rubygems.org/specs.4.8.gz)
The )uic' fi* is to install a new certificate into #uby" Download this certificate file( https(++raw"githubusercontent"com+rubygems+rubygems+master+lib+rubygems+ssl,c erts+inde*"rubygems"org+$lobalign#ootC."pem and place it into C:\Ruby23\lib\ruby\2.3.0\rubygems\sslcerts" /ote that your path may be different if you installed to another folder or installed a different version" &. 8 yo5=re on %in$ows> yo5=ll likely nee$ to install ?CC. recommen$ installing with Cygwin )https://cygwin.com/install.html*. %hen installing be s5re to select the F(evelF packages to have ?CC installe$. 'hen p5t the Cygwin bin 8ol$er in yo5r path> e.g. C:cygwin",bin.
How to Use Ceedling for Embedded Test-Driven Development
"
Creating a (ew Ceedling )ro*ect ;se the Gcee$ling new Hpro1ectameIG comman$ to create a new pro1ect: $ ceedling new MyProject create
MyProject/vendor/ceedling/docs/eedlingPac!et.pd"
create MyProject/vendor/ceedling/docs/#ception%ummary.pd" ... create MyProject/vendor/ceedling/vendor/unity/src/unity.h create MyProject/vendor/ceedling/vendor/unity/src/unity&internals.h create
MyProject/project.yml
create
MyProject/ra!e"ile.rb
Project 'MyProject' created( ) *ool documentation is located in vendor/ceedling/docs ) #ecute 'ra!e )*' to view available test + build tas!s
'his generates a pro1ect tree an$ the con8ig5ration 8iles nee$e$ to 5se Cee$ling. 0ro1ect creation only nee$s to be $one once when starting a pro1ect. mportant among the create$ 8ol$ers are: •
src: %here all o8 o5r so5rce 8iles will go.
•
b5il$: Contains anything generate$ by Cee$ling $5ring the b5il$.
•
test: %here o5r 5nit test 8iles will go.
ow we have a pro1ect in the GMy0ro1ectG 8ol$er. ote the instr5ctions 8rom the Cee$ling o5tp5t when we create$ the pro1ect -- we can 5se Grake -'G to show 5s how to 5se it: $ cd MyProject $ ra!e )* ra!e clean temporar...
, -elete all build arti"acts and
ra!e clobber build a...
, -elete all generated "iles and
ra!e environment variables
, ist all con"igured environment
ra!e "iles:header
, ist all collected header "iles
ra!e "iles:source
, ist all collected source "iles
ra!e "iles:test
, ist all collected test "iles
ra!e logging
, #nable logging
How to Use Ceedling for Embedded Test-Driven Development
ra!e module:create0module&path1 and tes...
, 2enerate module source3 header
ra!e module:destroy0module&path1 and test...
, -estroy module source3 header
ra!e paths:source
, ist all collected source paths
ra!e paths:support
, ist all collected support paths
ra!e paths:test
, ist all collected test paths
ra!e summary no bui...
, #ecute plugin result summaries
ra!e test: or sourc...
, 5un single test 01 real test
ra!e test:all
, 5un all unit tests
ra!e test:delta
, 5un tests "or changed "iles
ra!e test:path0dir1 contains 0dir...
, 5un tests whose test path
ra!e test:pattern0rege1 epressio...
, 5un tests by matching regular
ra!e verbosity0level1 obnoi...
, %et verbose output silent:061 )
ra!e version version in"o
, -isplay build environment
Cee$ling is b5ilt on 7ake> which is 75by=s $epen$ency-base$ b5il$ tool. Cee$ling an$ its 5nit test operations are implemente$ as ra+e tas+s. 'hese are the comman$s we will 5se to b5il$ an$ r5n o5r tests. /ote( ince we0re using #a'e we can e*tend our build capabilities by adding our own ra'e tas's to do whatever we would li'e1 e"g" generating documentation or downloading to the target"
How to Use Ceedling for Embedded Test-Driven Development
J
E,ample ./ 0tarting TDD with Ceedling n this example we=ll walk thro5gh a single '(( micro-cycle> a$$ing a 8eat5re by writing a test an$ getting it to pass. /ote that a new Ceedling pro2ect must have been created as described in the previous section"
Create a 1odule ow it=s time to write some co$e. magine we=re b5il$ing a car an$ we want to b5i l$ a mo$5le to implement the lighting system. %e create a mo$5le like this: $ ra!e module:create0lights1 2enerating 'lights'... m!dir )p ./test/. m!dir )p ./src/. 7ile ./test/./test&lights.c created 7ile ./src/./lights.c created 7ile ./src/./lights.h created
'his creates three 8iles: Glights.cG to implement o5r mo$5le> Glights.hG to $e8ine the p5blic inter8ace an$ a test 8ile where we can p5t the 5nit tests 8or it. 'hese 8iles are a5tomatically create$ in the correct 8ol$ers o8 o5r tree. /ote( 3e could also have provided a deeper path in which to create the module1 e"g" ra-e module:create.electrical$lights/" #t this point> we can try r5nning o5r 5nit tests: $ ra!e test:all *est 'test&lights.c' )))))))))))))))))))) 2enerating runner "or test&lights.c... ompiling test&lights&runner.c... ompiling test&lights.c... ompiling unity.c... ompiling lights.c... ompiling cmoc!.c... in!ing test&lights.out... 5unning test&lights.out...
How to Use Ceedling for Embedded Test-Driven Development
4
))))))))))) *#%* 9*P9* ))))))))))) 0test&lights.c1 )))))))))))))))))))) ;2<5#- *#%* %9MM=5> )))))))))))))))))))) 0test&lights.c1 *est: test&module&generator&needs&to&be&implemented =t line ?4@: ;mplement me( )))))))))))))))))))) A#5= *#%* %9MM=5> )))))))))))))))))))) *#%*#-:
?
P=%%#-:
6
7=;#-:
6
;2<5#-: ?
'his tells 5s that a single test was r5n an$ it was ignored . 'he module:create task has 5se$ a template to create the test 8ile. nsi$e the test 8ile testKlights.c is a single test name$ test&module&generator&needs&to&be&implemented which 5ses a special ignore $irective to tell Cee$ling to ignore this test. 'he 85nction looks like this: void test&module&generator&needs&to&be&implementedvoid@ B *#%*&;2<5#&M#%%=2#;mplement me(@C D
'his is the convention 8or 5nit tests which Cee$ling. 'est 8iles have names that start with test& an$ they go in the Btest 8ol$er. %ithin each o8 these 8iles> 5nit tests are 85nctions whose names start with test&. #lso in the test 8ile are the set9p@ an$ tear-own@ 85nctions. 'hese 85nctions are r5n be8ore an$ a8ter each o8 the test 85nctions in the test 8ile. 'hese 85nctions are yo5rs to 5se i8 yo5 nee$ them.
How to Use Ceedling for Embedded Test-Driven Development
!
Implement a 2eature ow that we have a mo$5le 8or the lights> it=s time to a$$ some 85nctionality. n the test$riven way> we=ll 8irst a$$ a test that $escribes some $esire$ behavior. Say we want this behavior: 3hen the headlight switch is off1 then the headlights are off" n this case we=re going to replace test&module&generator&needs&to&be&implemented@ with a new test 85nction: void test&Ehen*heFeadlight%witch;s""&*hen*heFeadights=re""void@ B // Ehen the headlight switch is o""... lights&%etFeadlight%witch""@C // then the headlights are o"". *#%*&=%%#5*G9="alse3 lights&=reFeadlightsn@@C D
%hat we=ve $one here is $e8ine two new 85nctions to implement in the lights mo$5le> lights&%etFeadlight%witch""@ an$ lights&=reFeadlightsn@. %e call the 8irst 85nction to t5rn the lights o88> an$ then call the secon$ to con8irm the state o8 the hea$li ghts. 'he *#%*&=%%#5*G9=@ macro is what we 5se to veri8y that the val5e ret5rne$ 8rom lights&=reFeadlightsn@ is the expecte$ val5e )"alse*. 'his is one o8 the many macros available 8or comparing vario5s types> all o8 which are explaine$ in the ;nity $oc5mentation )https://gith5b.com/'hrow'heSwitch/;nity/blob/master/$ocs/;nityL2S5mmary.p$8 *. ow we can r5n o5r tests> b5t obvio5sly this is going to 8ail with all kin$s o8 compilation errors> beca5se these 85nctions $on=t even exist yet. $ ra!e test:all *est 'test&lights.c' )))))))))))))))))))) 2enerating runner "or test&lights.c... ompiling test&lights&runner.c... ompiling test&lights.c... ... H %hell eecuted command: 'gcc.ee );test );test/support );src
);MyProject/vendor/ceedling/vendor/unity/src
How to Use Ceedling for Embedded Test-Driven Development
!!
);MyProject/vendor/ceedling/vendor/cmoc!/src );build/test/moc!s )-*#%* )-2<9&MP;#5 )g )c test/test&lights.c )o build/test/out/test&lights.o'
H =nd eited with status: 0?1. ra!e aborted( ... *as!s: *P IH build/test/results/test&lights.pass IH
build/test/out/test&lights.
out IH build/test/out/test&lights.o %ee "ull trace by running tas! with ))trace@ )))))))))))))))))))) A#5= *#%* %9MM=5> )))))))))))))))))))) )))))))))))))))))))) *#%*#-:
?
P=%%#-:
?
7=;#-:
6
;2<5#-: 6
'his may sort o8 8eel like we=re cheating> since lights&%etFeadlight%witch""@ $oesn=t act5ally $o anything an$ lights&=reFeadlightsn@ simply ret5rns "alse> b5t as we a$$ more tests we=ll contin5e to a$$ 85nctionality.
'epeat %e can now contin5e a$$ing B8eat5res to the mo$5le 5ntil it $oes every thing that we nee$ it to -- by a$$ing tests an$ then writing the co$e to make them pass. 6or example might want to implement this behavior: 3hen the headlight switch is on1 then the headlights are on" How to Use Ceedling for Embedded Test-Driven Development
!&
So> we create an a$$itional test: void test&Ehen*heFeadlight%witch;sn&*hen*heFeadights=renvoid@ B // Ehen the headlight switch is on... lights&%etFeadlight%witchn@C // then the headlights are on. *#%*&=%%#5*G9=true3 lights&=reFeadlightsn@@C D
8 we r5n this test it will 8ail beca5se lights&%etFeadlight%witchn@ $oesn=t exist yet> b5t when we 5p$ate lights.h: ,i"nde" lights&F ,de"ine lights&F ,include Jstdbool.hH void lights&%etFeadlight%witch""void@C void lights&%etFeadlight%witch""void@C bool lights&=reFeadlightsnvoid@C ,endi" // lights&F
#n$ a$$ the implementation in lights.c: ,include lights.h ,include Jstdbool.hH static bool areightsn I "alseC void lights&%etFeadlight%witch""void@ B areightsn I "alseC D void lights&%etFeadlight%witchnvoid@ B areightsn I trueC
How to Use Ceedling for Embedded Test-Driven Development
!,
D bool lights&=reFeadlightsnvoid@ B return areightsnC D
'hen we can r5n o5r tests an$ watch them both pass: $ ra!e test:all *est 'test&lights.c' )))))))))))))))))))) 2enerating runner "or test&lights.c... ompiling test&lights&runner.c... ompiling test&lights.c... in!ing test&lights.out... 5unning test&lights.out... ))))))))))) *#%* 9*P9* ))))))))))) 0test&lights.c1 K )))))))))))))))))))) A#5= *#%* %9MM=5> )))))))))))))))))))) *#%*#-:
L
P=%%#-:
L
7=;#-:
6
;2<5#-: 6
'efactoring Every time we get a test to pass> is an opport5nity to re8actor. Since we have a s5ite o8 passing tests> we can change the co$e in any way an$ we=ll imme$iately know i8 we broke something. 'his allows 5s the ability to 8reely experiment with improving the co$e> e.g. to make it simpler or easier to 5n$erstan$.
How to Use Ceedling for Embedded Test-Driven Development
!
7e8actoring can also be $one to the tests as well. Ao5 may notice that as yo5 a$$ more an$ more tests> some become re$5n$ant or yo5 en$ 5p with a lot o8 $5plication across tests. Ao5=ll want to keep this 5n$er control as yo5 work> so that they tests $on=t get too $i88ic5lt to 5n$erstan$.
How to Use Ceedling for Embedded Test-Driven Development
!"
1oc+ing Hardware Interfaces 9ow can yo5 5nit test yo5r embe$$e$ so8tware+ %hat abo5t yo5r har$ware $epen$encies+ 'he secret is moc'ing" %e can mock the inter8aces to o5r har$ware so that we dont need the actual hardware to test. 'his allows 5s to r5n o5r tests more D5ickly an$ be8ore the har$ware might even be available. 8 we=re $eveloping the so8tware 8or an embe$$e$ microcontroller> we=re probably going to be 5sing the microcontroller-provi$e$ har$ware mo$5les 8or things like S0> 2C> timers> etc.
6or each o8 these har$ware inter8aces> we want to have a correspon$ing so8tware mo$5le containing the microcontroller har$ware $epen$encies )i.e. har$ware register accesses*.
How to Use Ceedling for Embedded Test-Driven Development
!
%e can then mock each o8 these har$ware inter8aces> eliminating o5r har$ware $epen$encies b5t still allowing 5s to 5nit test o5r application. nstea$ o8 compiling these tests 8or the embe$$e$ microcontroller> we compile them 8or an$ r5n them on o5r host 0C.
'o help yo5 create yo5r mocks yo5 want to 5se a moc'ing framewor' . 'he mocking 8ramework incl5$e$ with Cee$ling is CMock. t allows yo5 to create mocks o8 in$ivi$5al so8tware mo$5les 8rom their hea$er 8iles. Ceedling improves the e,perience by automatically using C1oc+ to generating the moc+s that we need"
How to Use Ceedling for Embedded Test-Driven Development
!J
E,ample 3/ 1oc+ing a Hardware Interface with C1oc+ /ote that this e*ample assumes that we already have an e*isting Ceedling pro2ect" ee the section titles Creating a /ew Ceedling 4ro2ect if you need help" magine that we want to talk to an external 2C temperat5re sensor.
Create the Temperature 0ensor 1odule et=s create a mo$5le that will be o5r temperat5re sensor $river. $ ra!e module:create0temp%ensor1 2enerating 'temp%ensor'... m!dir )p ./test/. m!dir )p ./src/. 7ile ./test/./test&temp%ensor.c created 7ile ./src/./temp%ensor.c created 7ile ./src/./temp%ensor.h created
Write 4ur 2irst Test %hat is the 8irst thing want to be able to $o with this sensor+ =$ like to be able to rea$ the c5rrent temperat5re val5e. Cool. So take a look at the $atasheet 8or my 8ictional temperat5re sensor an$ can see that it How to Use Ceedling for Embedded Test-Driven Development
!4
has a b5nch o8 !"-bit registers -- each with J-bit a$$resses -- one o8 which is the temperat5re register. 'he scaling o8 the val5es is s5ch that a register val5e o8 is -!.NC an$ a register val5e o8 x&66 is O!,."NC. 'his makes each bit eD5ivalent to .2NC.
ow lets a$$ o5r 8irst test to testKtempSensor.c. want to know that when rea$ a temperat5re register val5e o8 x&66 that the temperat5re calc5late$ is !,.". void test&when*emp5egister5eadsMaAalue&then*he*emp;s*heMaAaluevoid@ B uint8&t temp5egister=ddress I 66C "loat epected*emperature I ?64.N"C "loat tolerance I 6.?"C //Ehen iLc&read5egisterpect=nd5eturntemp5egister=ddress3 6""@C //*hen "loat actual*emperature I temp%ensor&get*emperature@C *#%*&=%%#5*&7=*&E;*F;<tolerance3 epected*emperature3 actual*emperature@C D
6irst we set 5p some variables to hol$ o5r expecte$ val5es. 'hen in the FwhenF cla5se> we nee$ to sim5late )or mock* the 2C mo$5le ret5rning a val5e o8 x&88 on a rea$ o8 the temperat5re a$$ress. 6or the moment> we preten$ that there is another i2c mo$5le )it $oesn=t act5ally exist yet* which han$les the 2C comm5nication with the temperat5re sensor. 'his is where o5r har$ware $epen$ent co$e will event5ally go. So> the iLc&read5eadgisterpect=nd5eturn 85nction is act5ally a mock 85nction 5se$ to sim5late a call to a 85nction calle$ iLc&read5egister in the i2c mo$5le. %e=ll come back to this in a moment.
How to Use Ceedling for Embedded Test-Driven Development
2
'he FthenF cla5se is where we test that the tempSensor mo$5le act5ally ret5rns the correct temperat5re when we call temp%ensor&get*emperature. 'his 85nction $oesn=t exist yet either.
Create the 2unction Under Test ets create the temp%ensor&get*emperature 85nction with a $5mmy implementation: tempSensor.h: , i"nde" temp%ensor&F , de"ine temp%ensor&F "loat temp%ensor&get*emperaturevoid@C , endi" // temp%ensor&F
tempSensor.c: , include temp%ensor.h "loat temp%ensor&get*emperaturevoid@ B return 6.6"C D
1oc+ the I3C Interface 8 we try an$ r5n the test now> the compiler will complain that it $oesn=t know abo5t the iLc&read5eadgisterpect=nd5eturn mock 85nction. 'his is beca5se the iLc&read5egister 85nction $oesn=t exist an$ we haven=t yet tol$ Cee$ling to mock it. We dont actually need to implement this function however" Its enough to declare the function prototype in a header file and tell Ceedling to moc+ it with C1oc+" Create the hea$er 8ile> i2c.h: , i"nde" iLc&F , de"ine iLc&F , include Jstdint.hH uint?N&t iLc&read5egisteruint8&t register=ddress@C
How to Use Ceedling for Embedded Test-Driven Development
2!
, endi" // iLc&F
'he way we tell Cee$ling to mock this mo$5le is to a$$ this line to testKtempSensor.c: , include moc!&iLc.h
'his tells Cee$ling: 5ou 'now the i6c"h header you see over there7 3ell""" use C8oc' to generate the implementation and compile it in for us1 o'ay7 %hen CMock gets a hol$ o8 the hea$er 8ile it looks at all the 85nctions $e8ine$ there an$ generates several mock 85nctions 8or each... incl5$ing the iLc&read5egisterpect=nd5eturn 85nction we 5se$ in the test. 'his mock 85nction appen$s an a$$itional arg5ment to the original iLc&read5egister 85nction> which is the val5e we want the 85nction to ret5rn to the calling 85nction. 6or more $etails on all the mock 85nctions available with CMock> see the CMock $oc5mentation at: https://gith5b.com/'hrow'heSwitch/CMock/blob/master/$ocs/CMockKS5mmary.m$3generat e$-mock-mo$5le-s5mmary.
Implement the 2unction Under Test ow we can implement the logic 8or o5r temp%ensor&get*emperature 85nction. 5r new tempSensor.c is: , include temp%ensor.h , include iLc.h , include Jstdint.hH "loat temp%ensor&get*emperaturevoid@ B uint?N&t rawAalue I iLc&read5egister66@C return )?66.6" K 6.L" "loat@rawAalue@C D
8 we r5n o5r test> it sho5l$ pass now.
5dding 5nother Test %e=ll next want to a$$ more tests 8or other possible ret5rn val5es 8rom iLc&read5egister. 'his is easily $one by changing the ret5rn val5e provi$e$ to the mock 85nction. How to Use Ceedling for Embedded Test-Driven Development
22
6or example> to test that the minim5m temperat5re val5e is rea$ correctly: void test&when*emp5egister5eadsMinAalue&then*he*emp;s*heMinAaluevoid@ B uint8&t temp5egister=ddress I 66C "loat epected*emperature I )?66.6"C "loat tolerance I 6.?"C //Ehen iLc&read5egisterpect=nd5eturntemp5egister=ddress3 66@C //*hen "loat actual*emperature I temp%ensor&get*emperature@C *#%*&=%%#5*&7=*&E;*F;<tolerance3 epected*emperature3
actual*emperature@C
D
(ow we have a driver for an e,ternal hardware device that we can test without any of the hardware" %e can contin5e to $evelop the $river -- a$$ing more tests an$ 8eat5res -- by b5il$ing an$ testing on o5r host 0C. Py p5tting all o8 the microcontroller-$epen$ent 2C operations into their own mo$5le> we easily mocke$ them with Cee$ling an$ CMock. n 8act> we $i$n=t even have to implement this mo$5le yet -- we 15st ha$ to $e8ine its inter8ace in the hea$er 8ile. ;sing o5r mocks> we create$ 5nit tests that veri8y the behavior o8 o5r temperat5re sensor $river. 5s the rest of our application is developed! we can easily run these unit tests at any time to ma+e sure the driver will still wor+ correctly"
How to Use Ceedling for Embedded Test-Driven Development
2&
'eferences 0ource Code 'he so5rce co$e 5se$ in these examples is available on ?it95b. E,ample .
https://gith5b.com/ElectronQector/try-t$$-with-cee$ling
E,ample 3
https://gith5b.com/ElectronQector/mocking-har$ware-cee$ling-cmock
Documentation Ceedling
https://gith5b.com/'hrow'heSwitch/Cee$ling/blob/master/$ocs/Cee$ling0 acket.m$
Unity
https://gith5b.com/'hrow'heSwitch/;nity
C1oc+
https://gith5b.com/'hrow'heSwitch/CMock/blob/master/$ocs/CMockKS5m mary.m$
How to Use Ceedling for Embedded Test-Driven Development
2,
Ceedling 6uic+ 'eference ceedling new Jproject)nameH
Create a new Cee$ling pro1ect name$ Jproject)nameH.
ra!e )*
Show all available rake )Cee$ling* tasks 8or the pro1ect.
ra!e module:create0Jmodule)nameH1
Create a new mo$5le name$ Jmodule)nameH. Creates a so5rce 8ile> hea$er 8ile an$ 5nit test 8ile.
ra!e module:destroy0Jmodule)nameH1
(elete an existing mo$5le name$ Jmodule) nameH.
ra!e test:all
75n all 5nit tests in the pro1ect.
ra!e test:Jmodule)nameH
75n only the 5nit tests 8or this mo$5le.
ra!e clobber
(elete everything create$ $5ring the b5il$ o8 the tests. ike cleaning> b5t more.
Test 5ssertions *#%*&=%%#5*condition@
0ass i8 the con$ition is tr5e.
*#%*&=%%#5*&*59#condition@
0ass i8 the con$ition is tr5e.
*#%*&=%%#5*&7=%#condition@
0ass i8 the con$ition is 8alse.
*#%*&7=;@
6ail the test imme$iately.
*#%*&;2<5#@
# test containing this statement is ignore$.
*#%*&=%%#5*&7=*&E;*F;< delta3 epected3 actual@
0ass i8 the two 8loat val5e are within delta o8 each other.
*#%*&=%%#5*G9=&%*5;<2 epected3 actual@
0ass i8 the two n5ll-terminate$ strings match.
*#%*&=%%#5*G9=&%*5;<2&#< epected3 actual3 len@
0ass i8 the two strings match 5p to len.
How to Use Ceedling for Embedded Test-Driven Development
2
*#%*&=%%#5*&<9pointer@
0ass i8 the pointer is a n5ll pointer.
*#%*&=%%#5*&<*&<9pointer@
0ass i8 the pointer is not a n5ll pointer.
*#%*&=%%#5*G9=&M#M5> epected3 actual3 len@
0ass i8 the two regions o8 memory match.
*#%*&=%%#5*G9=&;<* epected3 actual@
0ass i8 the two signe$ integers match.
*#%*&=%%#5*G9=&9;<* epected3 actual@
0ass i8 the two 5nsigne$ integers match.
*#%*&=%%#5*G9=&;<*&=55=> epected3 actual3 elements@
0ass i8 the two arrays match.
&M#%%=2# can appen$e$ to any o8 the other
test assertions. 'hen there is on a$$itional arg5ment at the en$ o8 the arg5ment list which is a string to be printe$ i8 the test 8ails.
&M#%%=2#
6or the complete list o8 test assertions> see the ;nity $oc5mentation at: https://gith5b.com/'hrow'heSwitch/;nity.
1oc+ 2unction 2ormats 4riginal 2unction
C1oc+ 7enerated E,pect 2unction
void "uncvoid@
void "uncpectvoid@
void "uncparams@
void "uncpectepected¶ms@
retval "uncvoid@
void "uncpect=nd5eturnretval&to&return@
retval "uncparams@
void "uncpect=nd5eturnepected¶ms3 retval&to&return@
6or the complete list o8 available mock 85nctions> see the CMock $oc5mentation here: https://gith5b.com/'hrow'heSwitch/CMock/blob/master/$ocs/CMockKS5mmary.m$3generat e$-mock-mo$5le-s5mmary.
How to Use Ceedling for Embedded Test-Driven Development
2"