<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Peter's Blog - Nodes for testing</title>
    <link>http://www.petersblog.org/</link>
    <description>Nodes containing the tag testing</description>
    <item>
      <title>rspec</title>
      <link>http://www.petersblog.org/node/view/1630</link>
      <description>&lt;p&gt;
I've been trying out &lt;a href="http://rspec.info/"&gt;rspec&lt;/a&gt;, a new testing framework for &lt;a href="/tag/ruby"&gt;ruby&lt;/a&gt; that allows one to better follow the principles of Behaviour Driven Design (BDD). BDD is a step on from Test Driven Design (TDD) approach exemplified in the standard ruby unit test framework. TDD is the process of starting ones development by writing the tests that your new module should pass. As you write each test you then implement the code to pass it and hence, voila, you have nicely designed and robust software. In BDD you approach testing the code from how it is supposed to behave. When liasing with clients this is a better approach as everyone can talk in the same language, essentially in terms of requirements so one can try to get less bogged down in implementation details. 
&lt;/p&gt;
&lt;p&gt;
Here are some rspec tests for a class I have been working on: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; describe &lt;span class="Variable"&gt;ReportHelper&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt;   &lt;span class="Entity"&gt;before&lt;/span&gt;(&lt;span class="Constant"&gt;&lt;span class="Constant"&gt;:&lt;/span&gt;each&lt;/span&gt;) &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt; &lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt; &lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt; Create a new clean Report class for each individual test&lt;/span&gt;
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt; &lt;span class="Comment"&gt;    &lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt; &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;ReportHelper&lt;/span&gt;::&lt;span class="Entity"&gt;Report&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;   it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;should allow a column to be added&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  12 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  13 &lt;/span&gt;   it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;should allow multiple columns to be added&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  14 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  15 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Second Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  16 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  17 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  18 &lt;/span&gt;   it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;should allow rows to be added to the report&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  19 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  20 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Second Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  21 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddRow&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  22 &lt;/span&gt; &lt;span class="Comment"&gt;      &lt;span class="Comment"&gt;#&lt;/span&gt; pass&lt;/span&gt;
&lt;span class="line-numbers"&gt;  23 &lt;/span&gt;     &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  24 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  25 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  26 &lt;/span&gt;   it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;should only allow rows to be added if columns exist&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  27 &lt;/span&gt;     lambda{ &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddRow&lt;/span&gt;}.&lt;span class="Entity"&gt;should&lt;/span&gt; &lt;span class="Entity"&gt;raise_error&lt;/span&gt;(&lt;span class="Variable"&gt;RuntimeError&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;No columns defined&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  28 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  29 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  30 &lt;/span&gt;   it &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;should return simple cell values&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  31 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  32 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddColumn&lt;/span&gt;( &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Second Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;  33 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  34 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddRow&lt;/span&gt; &lt;span class="Keyword"&gt;do &lt;/span&gt;|&lt;span class="Variable"&gt;oRow&lt;/span&gt;|
&lt;span class="line-numbers"&gt;  35 &lt;/span&gt;       oRow[ &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;] &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;98&lt;/span&gt;
&lt;span class="line-numbers"&gt;  36 &lt;/span&gt;       oRow[ &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Second Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;] &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Constant"&gt;198&lt;/span&gt;
&lt;span class="line-numbers"&gt;  37 &lt;/span&gt;     &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  38 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  39 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;[&lt;span class="Constant"&gt;0&lt;/span&gt;][&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;].&lt;span class="Entity"&gt;should&lt;/span&gt; &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="Constant"&gt;98&lt;/span&gt;
&lt;span class="line-numbers"&gt;  40 &lt;/span&gt;     &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;[&lt;span class="Constant"&gt;0&lt;/span&gt;][&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;Second Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;].&lt;span class="Entity"&gt;should&lt;/span&gt; &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="Constant"&gt;198&lt;/span&gt;
&lt;span class="line-numbers"&gt;  41 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  42 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  43 &lt;/span&gt; &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;
Each test has a descriptive string that can be interpreted in two ways: as a test that must be passed or as a requirement for the software. The rspec toolset includes something that will pull out all these strings and give a summary of what testing has been done/what the requirements for the software are. If an auditor asks how the software is tested, bang, there is a full report of the tests. At a practical level (i.e. makes life easier for me) I prefer this to the ruby unit test system where one has to think up meaningful_method_names for each test. The strings are easier to write and read and reduce the need for comments. 
&lt;/p&gt;
&lt;p&gt;
Example report: 
&lt;/p&gt;
&lt;div class="verbatim-block"&gt;&lt;pre&gt;ReportHelper

- should allow a column to be added
- should allow multiple columns to be added
- should allow rows to be added to the report
- should only allow rows to be added if columns exist
- should return simple cell values
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
Rspec contains sweeter syntactic sugar than the ruby unit test module. For example, rspec overloads every object in the system with a 'should' method for doing the equivalent of assert tests: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;    &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;[&lt;span class="Constant"&gt;0&lt;/span&gt;][&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;].&lt;span class="Entity"&gt;should&lt;/span&gt; &lt;span class="Keyword"&gt;==&lt;/span&gt; &lt;span class="Constant"&gt;98&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;
Compare this to test/unit: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;    assert_equal &lt;span class="Constant"&gt;98&lt;/span&gt;, &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;[&lt;span class="Constant"&gt;0&lt;/span&gt;][&lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;First Column&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;]
&lt;/pre&gt;
&lt;p&gt;
apart from more typing, assert_equal has the expectation/actual things in what is intuitively to me the wrong order and I'm always having to correct these lines because the error messages have the terms swapped. 
&lt;/p&gt;
&lt;p&gt;
Rspec can test assertions more cleanly: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;    lambda{ &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddRow&lt;/span&gt;}.&lt;span class="Entity"&gt;should&lt;/span&gt; &lt;span class="Entity"&gt;raise_error&lt;/span&gt;(&lt;span class="Variable"&gt;RuntimeError&lt;/span&gt;, &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;No columns defined&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;/pre&gt;
&lt;p&gt;
although it's a pity that the lambda is necessary (and probably no 1 noob trap) but with test/unit the following always seemed like a lot of typing: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;    oError &lt;span class="Keyword"&gt;=&lt;/span&gt; assert_raises &lt;span class="Variable"&gt;RuntimeError&lt;/span&gt; &lt;span class="Keyword"&gt;do&lt;/span&gt;
      &lt;span class="Variable"&gt;&lt;span class="Variable"&gt;@&lt;/span&gt;oReport&lt;/span&gt;.&lt;span class="Entity"&gt;AddRow&lt;/span&gt;
    &lt;span class="Keyword"&gt;end&lt;/span&gt;
    assert_equal &lt;span class="String"&gt;&lt;span class="String"&gt;'&lt;/span&gt;No columns defined&lt;span class="String"&gt;'&lt;/span&gt;&lt;/span&gt;, oError.&lt;span class="Entity"&gt;message&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;
rspec is nicely integrated into &lt;a href="/tag/rails"&gt;rails&lt;/a&gt;, plugins being available to generate rspec tested controllers and models and suchlike, rake tasks to generate documents (woohoo) etc. It is integrated into &lt;a href="/tag/netbeans"&gt;netbeans&lt;/a&gt; and runs ok on Windows although when the tests are run (CTRL-F6) there is a tedious few seconds wasted in startup time. It is possible to run an rspec server in the background to eliminate this startup but it doesn't work on windows native ruby, it gives an error lamenting Microsofts glorious omission of a fork api. 
&lt;/p&gt;
&lt;p&gt;
There is much more to Rspec than this. One aim seems to be to write psuedo testing languages and have clients use these to write stories about what the software will do, these stories turning into a test framework. As the slashdot tag goes, 'goodluckwiththat'. At a practical level, I'm liking rspec even if only as a unit test framework with added syntactic sugar. 
&lt;/p&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/netbeans"&gt;netbeans&lt;/a&gt; &lt;a href="/tag/rails"&gt;rails&lt;/a&gt; &lt;a href="/tag/rspec"&gt;rspec&lt;/a&gt; &lt;a href="/tag/ruby"&gt;ruby&lt;/a&gt; &lt;a href="/tag/testing"&gt;testing&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1630</guid>
      <category domain="http://www.technorati.com/tag">netbeans</category>
      <category domain="http://www.technorati.com/tag">rails</category>
      <category domain="http://www.technorati.com/tag">rspec</category>
      <category domain="http://www.technorati.com/tag">ruby</category>
      <category domain="http://www.technorati.com/tag">testing</category>
    </item>
    <item>
      <title>Testing Firmware Code</title>
      <link>http://www.petersblog.org/node/view/1581</link>
      <description>&lt;p&gt;
&lt;a href="/node/1542"&gt;I've described before&lt;/a&gt; how I've been testing Firmware code written in C by compiling it into Ruby Extensions and using ruby's excellent unit testing framework. 
&lt;/p&gt;
&lt;p&gt;
Up till now I've been testing the 'middle tier' algorithmic code but how to go about testing the low level stuff, that which pokes the hardware? 
&lt;/p&gt;
&lt;p&gt;
The firmware I am developing is for the ST ARM750 microcontroller and I am using ST's own standard library which is very useful driver code for all the peripherals embedded on the chip. It is a very useful resource as the peripherals on this chip are very complex and the user manual is written in hardware engineer gobbledygook that you have to study like a legal document, looking for the small print (e.g. running it at 60MHz it kept crashing until I found the small print that advised me to enable 'burst mode'). 
&lt;/p&gt;
&lt;p&gt;
Scanning through the source to this library I saw some #ifdef DEBUG statements that implied that it could be compiled into an emulation library. The code was written very cleanly so it took me very little time to write something in (of course) ruby to scan the header files and generate 5250 lines of C code to emulate this library. Here is an example of one of the generated library functions: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt; &lt;span class="Comment"&gt; * Emulate the function TIM_ClearFlag&lt;/span&gt;
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt; &lt;span class="Comment"&gt; &lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt; &lt;span class="Keyword"&gt;void&lt;/span&gt; TIM_ClearFlag(TIM_TypeDef* TIMx, u16 TIM_FLAG)
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt; {
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt;   VALUE nRet;
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt;   VALUE oArgs = rb_ary_new();
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt;   VALUE strFuncName = rb_str_new2( &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;TIM_ClearFlag&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt;   ID nId = rb_intern( &lt;span class="String"&gt;&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;Function&lt;span class="String"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt;   rb_ary_push( oArgs, PassStructureArg( (&lt;span class="Keyword"&gt;void&lt;/span&gt; *)TIMx, &lt;span class="Keyword"&gt;sizeof&lt;/span&gt;( TIM_TypeDef)));
&lt;span class="line-numbers"&gt;  12 &lt;/span&gt;   rb_ary_push( oArgs, LONG2NUM( TIM_FLAG));
&lt;span class="line-numbers"&gt;  13 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  14 &lt;/span&gt;   nRet = rb_funcall( g_oCallBack, nId, &lt;span class="Constant"&gt;2&lt;/span&gt;, strFuncName, oArgs);
&lt;span class="line-numbers"&gt;  15 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  16 &lt;/span&gt;   &lt;span class="Comment"&gt;&lt;span class="Comment"&gt;/*&lt;/span&gt; nRet is not used &lt;span class="Comment"&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;  17 &lt;/span&gt; }
&lt;/pre&gt;
&lt;p&gt;
TIM_ClearFlag is the name of the function in the ST standard library. The emulation code takes the name of the emulated function and the two arguments to the function, converts them into ruby objects and passes them to a method called 'Function' in a ruby object. In the testing case, this object is something that will make sure the functions are being called in the correct sequence and with the correct parameters and will return the appropriate return value. Structure arguments are passed as binary objects which the ruby can decipher from the structure definitions in the ST library header files (also parsed using ruby). 
&lt;/p&gt;
&lt;p&gt;
Note that my system has a few limitations that are acceptable because of the simplicity of the ST library and the way it was coded: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
The parser I wrote just about handles the coding style of this library 
&lt;/li&gt;
&lt;li&gt;
The calls to ruby do not support the case where the library may poke the values within a structure passed to it by pointer. 
&lt;/li&gt;
&lt;li&gt;
It doesn't handle passing structures by value. 
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
Now I have my low level testing library I will be able to do my testing using something I call signature analysis (I'm not sure there is a better software engineering term). I write the code, test it on the real hardware, then I can record the sequence of function calls made including the values of function arguments. Later on, in leiu of real hardware to test it on I can run the test code and compare it against the previously recorded signatures. Et voila, the reassurance that I haven't broken anything and I can sleep at night. 
&lt;/p&gt;
&lt;p&gt;
UPDATE: 
&lt;/p&gt;
&lt;p&gt;
My test library now includes a YamlFaker that can be used in two modes: 
&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
it will record a sequence of function calls 
&lt;/li&gt;
&lt;li&gt;
it will ensure a sequence of function calls matches a previous recording 
&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;
The yaml script looks like this: 
&lt;/p&gt;
&lt;div class="verbatim-block"&gt;&lt;pre&gt;#
# This file is maintained by the YamlFaker module DO NOT EDIT
#
---
- test_CommandPWMSet Demand -200:
  - :Comment: |-

      Looking for demand to be correct according to the requested range and the
      scaling factors. Also ensure that for the fifth channel, the period is
      large for small demand as the output of this channel is inverted
  - TIM_SetPulse:
      args:
      - TIMx: TIM0
      - TIM_Channel: &amp;quot;0x2&amp;quot;
      - Pulse: &amp;quot;0x0&amp;quot;
  - TIM_SetPulse:
      args:
      - TIMx: TIM1
      - TIM_Channel: &amp;quot;0x2&amp;quot;
      - Pulse: &amp;quot;0x0&amp;quot;
  - TIM_SetPulse:
      args:
      - TIMx: TIM2
      - TIM_Channel: &amp;quot;0x2&amp;quot;
      - Pulse: &amp;quot;0x0&amp;quot;
  - PWM_SetPulse:
      args:
      - PWM_Channel: &amp;quot;0x2&amp;quot;
      - Pulse: &amp;quot;0x0&amp;quot;
  - PWM_SetPulse:
      args:
      - PWM_Channel: &amp;quot;0x4&amp;quot;
      - Pulse: &amp;quot;0x12c&amp;quot;
- test_CommandPWMSet Demand -100:
  - TIM_SetPulse:
      args:
      - TIMx: TIM0
      - TIM_Channel: &amp;quot;0x2&amp;quot;
      - Pulse: &amp;quot;0x0&amp;quot;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;
Most of the entries in the script describe the expected sequence of function calls, complete with arguments. I can ensure that the demand being sent to my PWM channels is what I expect. These recorded scripts could be quite useful, it is a complete log of the interaction with the hardware. If I ever had to change the code that poked the hardware I can compare the script recorded from the new code against my old script and make sure that any changes are what I would expect. This way I can be far more certain that my changes are correct before they hit real hardware. 
&lt;/p&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/c"&gt;c&lt;/a&gt; &lt;a href="/tag/ruby"&gt;ruby&lt;/a&gt; &lt;a href="/tag/testing"&gt;testing&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1581</guid>
      <category domain="http://www.technorati.com/tag">c</category>
      <category domain="http://www.technorati.com/tag">ruby</category>
      <category domain="http://www.technorati.com/tag">testing</category>
    </item>
    <item>
      <title>Testing 123</title>
      <link>http://www.petersblog.org/node/view/1537</link>
      <description>&lt;p&gt;
I've really got into Unit Testing now. The Ruby Unit Testing framework makes it very easy. I've tried unit testing in the past on C++ projects but the lack of a good framework there meant that coding the tests was more laborious than coding the code it was testing. 
&lt;/p&gt;
&lt;p&gt;
So far I've written a Bootloader than downloads Hex files to the target firmware. It consists of the following modules: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
low level rs232 extension written in C++ and &lt;a href="/tag/swig"&gt;swig&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
higher level rs232 port abstraction written in ruby 
&lt;/li&gt;
&lt;li&gt;
Boot Loader modules to interface with the boot loader firmware embedded in the ARM7 microcontroller 
&lt;/li&gt;
&lt;li&gt;
Intel Hex file decoder 
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
I have been able to test these as follows: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
a test harness to test the low level RS232 extensions by using an RS232 loopback connection 
&lt;/li&gt;
&lt;li&gt;
a test harness to test the higher level RS232 abstration using an RS232 loopback connection 
&lt;/li&gt;
&lt;li&gt;
a test harness to test the Boot Loader module against the real microcontroller 
&lt;/li&gt;
&lt;li&gt;
a test harness to test the Boot Loader module against a 'fake' rs232 port 
&lt;/li&gt;
&lt;li&gt;
a test harness to test the parsing of Intel Hex files 
&lt;/li&gt;
&lt;li&gt;
a test harness to download a 'known good' intel hex file to the microcontroller 
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
I am able to test automatically just about anything here in one of three modes: 
&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;
with the real microcontroller, real rs232 
&lt;/li&gt;
&lt;li&gt;
rs2332 loopback 
&lt;/li&gt;
&lt;li&gt;
'fake' 
&lt;/li&gt;&lt;/ol&gt;

&lt;p&gt;
The 'faker' is what a call a class that is able to emulate a port. Initially I wrote it to emulate an RS232 port in the following way: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
the 'faker' would receive what was being output to the port and check that it was correct 
&lt;/li&gt;
&lt;li&gt;
the 'faker' was able to simulate data being returned from the port 
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
I created a faker that parsed the input and output data from a IO class and hence could test the Bootstrap commands with a fake rs232 port like this: 
&lt;/p&gt;
&lt;pre class="lazy"&gt;&lt;span class="line-numbers"&gt;   1 &lt;/span&gt; &lt;span class="Comment"&gt;  &lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   2 &lt;/span&gt; &lt;span class="Comment"&gt;  &lt;span class="Comment"&gt;#&lt;/span&gt; Test the Get command&lt;/span&gt;
&lt;span class="line-numbers"&gt;   3 &lt;/span&gt; &lt;span class="Comment"&gt;  &lt;span class="Comment"&gt;#&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   4 &lt;/span&gt;   &lt;span class="Keyword"&gt;def&lt;/span&gt; &lt;span class="Entity"&gt;test_get&lt;/span&gt;
&lt;span class="line-numbers"&gt;   5 &lt;/span&gt;     strConversation &lt;span class="String"&gt;&lt;span class="String"&gt;= &amp;lt;&amp;lt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;   6 &lt;/span&gt; &lt;span class="String"&gt;# connect&lt;/span&gt;
&lt;span class="line-numbers"&gt;   7 &lt;/span&gt; &lt;span class="String"&gt;&amp;lt; 0x7f&lt;/span&gt;
&lt;span class="line-numbers"&gt;   8 &lt;/span&gt; &lt;span class="String"&gt;&amp;gt; 0x75&lt;/span&gt;
&lt;span class="line-numbers"&gt;   9 &lt;/span&gt; &lt;span class="String"&gt;# command&lt;/span&gt;
&lt;span class="line-numbers"&gt;  10 &lt;/span&gt; &lt;span class="String"&gt;&amp;lt; 0x01&lt;/span&gt;
&lt;span class="line-numbers"&gt;  11 &lt;/span&gt; &lt;span class="String"&gt;# data&lt;/span&gt;
&lt;span class="line-numbers"&gt;  12 &lt;/span&gt; &lt;span class="String"&gt;&amp;gt; 0x11 0x00 0x00 0x75&lt;/span&gt;
&lt;span class="line-numbers"&gt;  13 &lt;/span&gt; &lt;span class="String"&gt;&lt;span class="String"&gt;EOF&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;  14 &lt;/span&gt;     oFd &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;StringIO&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;( strConversation)
&lt;span class="line-numbers"&gt;  15 &lt;/span&gt;     oPort &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Variable"&gt;RS232Faker&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;
&lt;span class="line-numbers"&gt;  16 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  17 &lt;/span&gt;     oPort.&lt;span class="Entity"&gt;Run&lt;/span&gt;( oFd) &lt;span class="Keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;  18 &lt;/span&gt;       oBoot &lt;span class="Keyword"&gt;=&lt;/span&gt; &lt;span class="Support"&gt;BootLoader&lt;/span&gt;.&lt;span class="Entity"&gt;new&lt;/span&gt;
&lt;span class="line-numbers"&gt;  19 &lt;/span&gt;       oBoot.&lt;span class="Entity"&gt;Connect&lt;/span&gt;( oPort)
&lt;span class="line-numbers"&gt;  20 &lt;/span&gt;       oResults &lt;span class="Keyword"&gt;=&lt;/span&gt; oBoot.&lt;span class="Entity"&gt;CommandGet&lt;/span&gt;
&lt;span class="line-numbers"&gt;  21 &lt;/span&gt; 
&lt;span class="line-numbers"&gt;  22 &lt;/span&gt;       assert_equal [&lt;span class="Constant"&gt;0x11&lt;/span&gt;,&lt;span class="Constant"&gt;0x00&lt;/span&gt;,&lt;span class="Constant"&gt;0x00&lt;/span&gt;], oResults
&lt;span class="line-numbers"&gt;  23 &lt;/span&gt;     &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;  24 &lt;/span&gt;   &lt;span class="Keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;
Lines in the fake script that start with a '&lt;' is data that should be transmitted and lines that start with a '&gt;' should be received. 
&lt;/p&gt;
&lt;p&gt;
The Bootloader module itself is written such that it can connect to either a real rs232 port or this fake one. 
&lt;/p&gt;
&lt;p&gt;
Within the Bootloader modules was a particularly complex method that converted memory address ranges into an array of sector numbers that needed erasing. I exposed this method so that I was able to test it specifically in the Unit Test. 
&lt;/p&gt;
&lt;p&gt;
The faker can be generalised beyond rs232 to handle anything that inputs and outputs. It doesn't even need to run a fixed script, it could contain heuristics to emulate hardware such as a temperature control channel and test whether the code does actually control temperatures. 
&lt;/p&gt;
&lt;p&gt;
I'm toying with the idea of testing my embedded C code by compiling it into a Ruby extension and calling it from Ruby Test Harnesses. The code would be compiled by gpp both for the ruby extension and the real hardware. This should provide thorough testing of the logical aspects of the code (e.g. servo control calculations) and may only be lacking in the following areas: 
&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;
it would not test the 'real time' aspects of the C code (interraction with interrupts etc) 
&lt;/li&gt;
&lt;li&gt;
it would not test for problems in the code generation for the real firmware 
&lt;/li&gt;
&lt;li&gt;
it would not test for differences between the processor architectures, e.g. number of bits in an integer, although the ARM is a 32 bit microcontroller. 
&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;
However, this should provide a satisfying amount of testing. 
&lt;/p&gt;
&lt;p&gt;
Another problem with this is that I would have ruby calling a ruby extension in C which would in turn call 'faker' objects written in ruby. I am unsure how to go about doing this and I am unsure whether the faker objects would be able to raise exception back up to the main ruby script. It may be able to do this in a flaky and memory-leaking way but that isn't too much of a problem in a test harness: I am testing the algorithms, not the memory leaks in the test harness. 
&lt;/p&gt;
&lt;p&gt;
Conclusion: Unit Testing FTW 
&lt;/p&gt;&lt;p&gt;Related Posts: &lt;a href="/tag/ruby"&gt;ruby&lt;/a&gt; &lt;a href="/tag/testing"&gt;testing&lt;/a&gt; &lt;a href="/tag/unit"&gt;unit&lt;/a&gt;&lt;/p&gt;</description>
      <guid>http://www.petersblog.org/node/view/1537</guid>
      <category domain="http://www.technorati.com/tag">ruby</category>
      <category domain="http://www.technorati.com/tag">testing</category>
      <category domain="http://www.technorati.com/tag">unit</category>
    </item>
  </channel>
</rss>
