![]() |
Articles Feed |
Categories
Archives
- March 2010 (1)
- February 2010 (2)
- January 2010 (1)
- December 2009 (1)
- October 2009 (4)
- September 2009 (2)
- August 2009 (2)
- July 2009 (5)
- June 2009 (2)
- May 2009 (2)
- April 2009 (8)
- March 2009 (7)
- January 2009 (2)
- December 2008 (3)
- November 2008 (5)
- October 2008 (4)
- September 2008 (6)
- August 2008 (4)
- July 2008 (5)
- June 2008 (5)
- May 2008 (4)
- April 2008 (2)
- February 2008 (4)
- January 2008 (2)
- December 2007 (2)
- November 2007 (2)
- October 2007 (2)
- September 2007 (1)
- August 2007 (3)
- July 2007 (1)
- June 2007 (4)
- May 2007 (7)
- April 2007 (2)
- February 2007 (3)
- January 2007 (3)
- November 2006 (3)
- October 2006 (3)
- September 2006 (17)
- November 2004 (1)
When is a Mock not a Mock
by: eric | January 10th, 2009 | 0 comments »
A couple of weeks ago I had to add a feature to some code that was written almost two years ago. It was a pretty simple web service client that constructed some XML, using Ruby’s REXML library, and made the web service call via another library. A quick inventory shows two dependencies, the web service call and REXML, so that’s what I expected to see when I came across the tests. But what did I see? Paraphrasing:
- @client_under_test = Client.new
- @client_under_test.stub!(:send_message)
- @client_under_test.stub!(:parse_response)
Of course the send_message call contained the construction of the XML so that there was no test that the XML being constructed was correct. Heck that was all that was being done in the class, and a closer inspection of the tests revealed that all they were doing was testing the error handling by changing the return value of parse_response. This is a classic sign that the developer at the time couldn’t figure out how to stub out the actual dependency, and so they did the next best thing, they stubbed out the caller.
I knew this was wrong, but I had an iteration meeting the next day and still had to update the .NET web service that this code was calling. So I started to just go ahead and make the untested change, but then my Clean Code wristband started burning until I couldn’t take it any more. I had to get the REXML library under test. So what to do? Well the REXML construction looked like this:
- doc = REXML::Document.new(create_schema)
- doc.elements["name1"].text = "thing 1"
- doc.elements["name2"].text = "thing 2"
- ...
Okay I know how to do this normally. The first test was simple:
- REXML::Document.should_receive(:new).with(schema)
It passed! What was so hard about testing this anyway? Okay let’s test that the elements are set:
- ....
- elements = mock(REXML::Document, :[] => mock_element)
- doc = mock(REXML::Document, :elements => elements)
- REXML::Document.stub!(:new).with(schema).and_return(doc)
- ...
Oh that sucks! Since the API doesn’t run entirely through the doc object I have to stub elements, then stub each individual element, then should_receive on text, and if I want to be perfect I can stub out the array accessor too. I have to should_receive for each element name, the tests will be hard to follow and fragile. Now I get why the original developer punted on this. There’s got to be a better way. I can start expecting actual XML, but from past experience I know that leads to very hard to read tests that give errors that aren’t easy to diagnose. What I really care about is that the elements in this hash-like structure have their text element set to the right data. After trying out several approaches I had a moment of inspiration, I want a struct! Must be my inner C programmer. If elements was a hash of structs, I could just check their text values are set. This way I’m testing that I’m using the REXML library right rather than testing the library itself. If only Ruby had a struct concept…..
I suppose you’ve already figured out that it does, haven’t you?
- MockElement = Struct.new("MockElement", :text)
What that does is setup a class named MockElement, with the accessor text. When is a Mock not a Mock? When it’s really a Fake. Instead of stubbing out elements to return yet another mock, elements will return a hash of the element names I know I’m using that point to these fake elements. Then after making the call in the client, I’ll just check that the text is set properly. This is best demonstrated with an example:
- before(:each) do
- @elements = initial_elements_hash
- @doc = mock(REXML::Document, :elements => @elements)
- REXML::Document.stub!(:new).with(schema).and_return(@doc)
- end
- def initial_elements_hash
- return {"element1" => MockElement.new,
- "element2" => MockElement.new}
- end
- it "should set the data in the xml doc" do
- @client.send_message
- @doc.elements["element1"].text.should == "Eric"
- @doc.elements["element2"].text.should == "Smith"
- end
Aha! Now I’ve tested that the XML was properly constructed without relying on looking at the actual XML text itself and without stubbing out the class itself. The code is cleaner, the tests are easier to understand, and I can implement my new feature. More importantly, my wristband stopped burning.
Embedded Ruby Talks Morse
by: doug | January 8th, 2009 | 6 comments »
I've been working with Ruby on embedded systems for a couple of weeks now. The final pieces have fallen into place and I'd like to share them with you. From the beginning of the project, my goal have been to turn some LEDs on and off from a web page.
Getting down to the metal
Any embedded software application has to eventually control some interesting hardware. My ARM board had two LEDs wired up, so I thought I'd try to control them. The control for the ports that control those LEDs are in memory mapped registers. Ruby really never let's us see the memory that we are working with, and even if it did, we are working in a virtual memory environment, so we wouldn't be able to access the specific memory address where the register is located. So it was time to learn how to write Ruby extensions.
I was surprised how easy this ended up being. Ruby has a great little module 'mkmf' that makes Makefiles for you. The API for defining ruby modules was also pretty straight forward and explained well in Pickaxe. I put the module I wrote up on git hub, so take a look there if you are interested. The extension allows you to just read from or write to any physical address on the device. To set a bit in a register, you might do something like this.
- include MemoryMappedIO
- from_register = read(0x560000010, "w")
- write(0x560000010, "w", from_register | 0x00000001)
Ahh. . 0x, hex numbers, addresses. It's nice to be back.
To get the module into my Ruby environment, I created an 'mmio' directory in the 'ext' directory of the Ruby source and dropped in the source files. I didn't have to change any makefiles, I just created an extconf.rb and the ruby build system took care of the rest. It would certainly be possible to build the module separate from the rest of the Ruby source, but since I already had the source tree configure to cross-compile, the path of least resistance was to just include this extension in the source tree.
I posted my extension to the ruby-core mailing list to see if there was any wider interested in it. It turns out there is a memory mapper extension already written. I took a quick look and it isn't exactly the same thing that I did. My interface is much more basic (and simple), but I think the mmap extension could be made to do the same thing I am doing.
The Promised Land
With a way to control the hardware from Ruby, I had finally arrived where I had wanted to be. The entire thesis behind this little experiment was that Ruby could make embedded application development fast and fun. I found both to be true. This entire application came together in just a couple of hours. I was able to make use of a ruby gem that did a bunch of the work for me. I called the application weblink. You are free to interpret the name however you would like (We Blink, Web Blink, Web link). The source is on git hub.
When test-driving an embedded system, you'll save yourself a bundle of time by doing as much of the development as you can on your host computer. The download, restart, test cycle can really add up when you are working in quick TDD cycles. On my particular system, the files system is still being hosted remotely, and the language is interpreted (no compile) so this overhead is not that bad. Still I wanted my application to run on my development machine, and I didn't think it wise to overwrite some random address in my Mac's memory, so I needed an abstraction.
When developing these kinds of environments in a C++ system, I would traditionally build a pure-virtual interface and implement it twice, once for the target hardware and once for the simulated, or development environment. In C you can do a similar thing with the linker. You write two functions, one for each platform and just link in the correct one when building for that platform. With Ruby's ducktyping, there is no need for a defined interface, but the concept is very similar.
I wrote two Led classes both with 'on', 'off', and 'on?' methods. The MockLed class just saves the on/off state in a YAML file. The real Led class uses the mmio extension to read and write a bit in a memory mapped register. I did not want the real Led class to have the platform specific knowledge about which LEDs were in which register, so I used the Factory Pattern to create the Led objects. The factory method is called 'find.' The MockLed file implements this same method that returns MockLed objects in the development environment.
The tricky part of this is switching between the two Led classes. For this, I chose to use Sinatra's environment configuration scheme. The production environment is used when running the app on the target, and the development environment runs on my Mac.
- configure :production do
- require 'leds_S3C2440A'
- end
- configure :development do
- require 'mock_led'
- end
Dit, Dash
To celebrate the 170th anniversary of the first demonstration of the telegraph, I decided to turn the application into a visual telegraph, beeping out little messages. The ideas is that you enter a message in the web page, and the LED blinks out your morse code. Here is where I saw the great power of not only Ruby, but also the community who uses it. I discovered right away that there is a Morse Code Gem already written. You give it a string and It gives you back a series of dits, dashes, and spaces. Thanks Ben!
Eric Meyer sat down with me and we ping-ponged out the morse blinker in short order. I love how simple this class ended up. It just proves again to me what great code you can write in Ruby.
See it for yourself
Okay, so enough talking, let me show it to you. Enjoy.
A Screenshot of the app:
What's Next
So I know that the response that I will get from embedded developers is "Great, but it's slow and big, it can't be used in a real system." I'm going to do some profiling and optimization on this system to get some hard performance data. Initial results (just looking at 'top') shows that the ruby process with Sinatra, Webrick, the morse gem, and my code loaded up is taking up about 12% of the system memory. That mean about 6 or 7 MB. What nice is that you only pay for what you use. If you don't require it, it won't load into memory.
As far as clock cycles go, the ruby processes peaks out at about 20% of the 400 MHz processor when serving HTTP requests. While blinking the LEDs, only a fraction of a percent of the processor's cycles are being consumed. I'm not happy with the performance of Webrick (no one ever claimed it was fast anyway) and I am going to try to get Sinatra running with 'Thin' instead.
Synchronization: I fork a new ruby process to blink out the messages. If you got both LEDs blinking at the same time, they could step on each other's toes and cause incorrect values to be written to the LED. I need to stick a mutex in to protect that register.
I remember early in my career, Kevin Moore and I had started using Ruby to run our embedded builds. We used the Win32 API to drive the automation interface of Metrowerks and we wrote lots of little tools to do the annoying parts of building a flash image for us. I remember at the time, Kevin and I having a conversation that went something like "Wouldn't it be cool if we could write the entire app in Ruby?" Well Kevin, now we can.
#