Unit Testing iPhone apps with Ruby: rbiphonetest

Posted by Dr Nic on July 04, 2008

rbiphonetest logo

Everything to love about Ruby: the concise, powerful language; the sexy testing frameworks; and finally, the people.

Everything to love about Objective-C: hmmm; well…; and finally, its the only high-level language you can use to write iPhone apps.

On iPhone 2.0, to arrive on the 11th of July, you cannot run RubyCocoa. But you can run it on your Mac, so let’s use it to unit test your Objective-C classes. This tutorial shows you how to get started using a new project rbiphonetest [GitHub | Lighthouse | Google Group]

If you followed some of my recent tweets, this project was previously called “iphoneruby”. And alas, the screencast also calls it “iphoneruby” but that was a crap name. People thought it was a way to run Ruby on the iphone. I can’t do that yet. So, a far better name is ‘rbiphonetest’. [track on summize]

Even if you’ve never touched Objective-C, Cocoa, the iPhone SDK, nor RubyCocoa I recommend watching the video anyway. It should give you hope that if you make the transition to iPhone development you don’t have to go alone without Ruby: your trusty swiss army knife of language/libraries/tools.

The screencast is also available in high-def video (55Mb QuickTime)


Unit Testing iPhone apps using Ruby from Dr Nic on Vimeo.

Installation and Usage

To summarize the video, but change ‘iphoneruby’ to ‘rbiphonetest’, you install the framework via RubyGems:

sudo gem install rbiphonetest

Then change to your project’s folder and install the test framework:

rbiphonetest .

Finally, for each generic, non-UIKit-framework-using class you want to test:

script/generate model WidgetModel

Then write your tests in test/test_widget_model.rb

Supported Cocoa & iPhone frameworks

The mysterious, magical premise upon which rbiphonetest depends is possibly erroneous: that your Objective-C class can be compiled and tested against your OS X/Intel frameworks, and if your tests pass you assume you can then compile and include your class with the the iPhone/ARM frameworks.

I’m willing to go with this assumption until its proven dangerously flawed by some angry 20-year veteran of NextStep/Cocoa/iPhone. But really, how different could NSString be on the iPhone versus your Mac?

Fortunately there is one way to check for significant differences between your available Mac-based frameworks, such as Cocoa, and the iPhone-based frameworks, such as UIKit. We need to compare the framework names, header files and method signatures.

So for example, you cannot currently unit test any class that depends on/includes the UIKit framework. Why? It doesn’t exist on your Mac, so the Mac/Intel compiler cannot link it in. We’re compiling and running our tests with RubyCocoa, which itself is built against the Mac/Intel frameworks, not the iPhone frameworks. Hell, Laurent doesn’t even own an iPhone :) [Laurent is the Apple-employee maintainer of RubyCocoa and the newer MacRuby]

Similarly, its no use including/linking the Cocoa framework into your Objective-C class. Why? It doesn’t exist on the iPhone. It has its own UI frameworks, collectively called ‘UIKit’.

So for the moment we cannot test UI-related, iPhone-API-specific code. But we can test generic Objective-C. That’s better than a kick in the teeth. Surely. I mean, in the teeth… that’d friggin’ hurt.

“Fair enough Dr Nic, so which frameworks can my code use and yet still unit test it with your oh-so-special test library thingy?” Keep your pants on, I’m getting there. [ref]

To the best of my ability, I’ve compared the two sets of frameworks and listed the available Frameworks that are available on both the iPhone and your Mac. There are about a dozen. The most important is called ‘Foundation’. It holds gold nuggets like ‘NSString’.

The list of platform differences is on the wiki as a reference.

Note, this list doesn’t guarantee that any two framework classes - the iPhone and matching Mac framework - will behave the same. This list is compiled by finding the set of Frameworks with the same name on both platforms, e.g. Foundation.

Then it compares the set of public header files (Foundation.framework/Headers/*.h files) This comparison is by method signature. It pulls all lines from each header that start with + or - (+ is a class method and - is an instance method in Objective-C) and compares the two lists. If there is a single difference in the method signatures of the header files in the two platforms it is marked on the wiki page. You’ll need to look at the two header files yourself to see the differences. Some header files are ugly. C-based anything starts ugly and goes down from there, I think.

Python testing of iPhone Objective-C?

In the Python world there is PyObjC, a bridge-based twin to RubyCocoa. If you are a Python developer you could easily port this project to use PyObjC I would think. Ping me if you are attempting this and need any help.

Summary

I think this project can give Ruby developers a happy place to work from as they write their Objective-C/iPhone code. You still need to wire up your UI views and controller classes manually, but if you push all the “oooh that code really needs some tests” classes away from the UI-dependent frameworks then you can hook it up to rbiphonetest and write your tests in Ruby.

Currently the generator creates test/unit test stubs. I personally then add the Shoulda gem into my test_helper.rb for my apps. If an rspec and/or test/spec developer can help with adding support to the generators I’m certain the large rspec user-base would be happy campers.

Similarly, someone might like to investigate using MacRuby to run the tests instead of RubyCocoa. Fast tests vs slow tests. You choose.

What the?

Sometimes I re-read what I’ve written and notice things that don’t seem to make sense, but are in my vocabulary nonetheless. Yep, the things you learn living in Australia.

“Keep your pants on” - this seems to imply that until I mentioned otherwise you were about to take your pants off. Hardly relevant at any stage during this article, we’d both agree. Most code-based blog articles are “pants on”. This phrase means “don’t get upset”. You can try to figure out how you go from “don’t get upset” to “keep your pants on”. I have no idea.

Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Chris Fri, 04 Jul 2008 05:50:29 UTC

    BTW Nic, you can easily use C/C++ on the iphone just like you would on a normal mac. The only thing you actually need to use ObjC for is to talk to the Cocoa APIs.
    It very straight forward to turn on ObjC++ just change a .m file to .mm and you can mix and match from all 3 languages at will for what ever is best for the current job.

  2. José Valim Fri, 04 Jul 2008 07:51:28 UTC

    Nice! =)
    But I do think it is easier to get upset with pants on than off!

    (Sorry, but I had to drop this comment! =P)

  3. Aaron VonderHaar Fri, 04 Jul 2008 10:12:13 UTC

    Hi Dr Nic, Thanks for starting this project! I’ve been wanting to do ruby testing of my cocoa apps for a while, but I never figured out how to compile bundles and load them into RubyCocoa.

    I was playing around with this last night, and I got some rspec specs and stories running with your framework. I’ve posted the code here: http://github.com/avh4/rbiphonetest-example/commits/rspec

    I’d be glad to help however I can to add add rspec support to rbiphonetest.

  4. Dr Nic Fri, 04 Jul 2008 10:16:21 UTC

    @aaron - awesome; we’ll talk about it on the mailing list. Ultimately I need to fragment out the test/unit stuff into specific generators and use rubigen dependencies. Fortunately merb + newgem have done this in the past so we can steal those ideas.

  5. Dr Nic Fri, 04 Jul 2008 12:26:20 UTC

    Apple has a page describing differences between OS X and iPhone frameworks: iPhoneOS for Cocoa Developers

  6. A Fresh Cup » Blog Archive » Double Shot #241 Fri, 04 Jul 2008 21:02:15 UTC

    [...] Unit Testing iPhone apps with Ruby: rbiphonetest - Does Dr. Nic ever sleep? [...]

  7. Jon Hohle Fri, 04 Jul 2008 21:36:47 UTC

    Since you cannot test iPhone specific libraries anyway, why not use the built in otest for writing unit tests?

  8. Dr Nic Fri, 04 Jul 2008 23:45:07 UTC

    @Jon - ultimately its a starting point for pushing RubyCocoa closer to the UIKit frameworks; perhaps onto the iPhone itself one day. I find Ruby cleaner and more concise for writing code that also communicates what it is doing; I also love the Ruby-based test frameworks such as rspec and test/unit, and the surrounding tools (such as autotest).

    I figured it would be beneficial to release the tool now, even without full UIKit coverage.

    But, people already familiar + happy with one of the current Objective-C test suites would probably keep using those. I’ll probably investigate these test suites soon to see how easy they make UI testing etc.

    Again, I prefer writing/reading Ruby, so I want to get as much Ruby into my development code, tests and support tools as possible. It makes me happy and productive.

  9. Justin Palmer Sat, 05 Jul 2008 05:04:20 UTC

    Great stuff Nic! There is a tool that’s used in the Rakefiles generated by RubyCocoa which allows you to programatically add files to an XCode project. You could likely use this instead of manually adding the files:
    https://rubycocoa.svn.sourceforge.net/svnroot/rubycocoa/trunk/src/framework/tool/rubycocoa/

  10. Grammar Police Sat, 05 Jul 2008 09:36:07 UTC

    You may “infer” something when you hear a message; you can “imply” something when you send a message (and you might judge the implication to exist in the message independent of the sender’s intent to put it there). Your last paragraph should start:
    *“Keep your pants on”* - this seems to *imply* that until I mentioned otherwise you were about to take your pants off.

  11. Dr Nic Sat, 05 Jul 2008 12:42:32 UTC

    @Justin, ahh thanks for pointing those helper libraries out. When I did the video originally and I got to the final linking error I actually didn’t know what I’d done wrong. And linking errors are annoying. The section where I fix the linking error was cut into the video later when I figured it out. I definitely want the generated files to be auto-added to the xcode project, so I’ll reuse the RC tools code; thx for pointing out where it is.

  12. Dr Nic Sat, 05 Jul 2008 15:24:11 UTC

    @GP, I’ll take any grammar advice on offer. Thanks.

  13. rbiphonetest: Unit Testing iPhone Apps with Ruby Mon, 07 Jul 2008 01:43:36 UTC

    [...] lately and, unsurprisingly, has found a way to bring Ruby into the mix. He has developed rbiphonetest, a Ruby-based testing framework for iPhone / Objective C applications that uses RubyCocoa to [...]

  14. Peter Jaros Mon, 07 Jul 2008 06:29:49 UTC

    Awesome! I was preparing to do the exact same thing after WWDC, but I ran into some snags. I’m glad I didn’t duplicate your efforts!

    Quick question, though: what does this have to do with the iPhone in particular? Aren’t you just unit testing Obj-C classes in Ruby? I mean, it’s great that it *does* work for iPhone development, but this would be great for desktop Cocoa development too.

  15. Dr Nic Mon, 07 Jul 2008 08:50:32 UTC

    @peter - it can definitely be used for mac cocoa development too (I think mention it a couple times to cover my bases). I didn’t figure too many people would use it for that, since with Cocoa development you have the option to write the whole app in RubyCocoa or in the future, MacRuby.

    Nonetheless, Aaron VonderHaar has used it for some projects (http://groups.google.com/group/rbiphonetest/msg/81a21d5d304fb239) and has some thoughts on mocking NSObject subclasses.

    If lots of people use it for Cocoa dev then we can talk about changing the project name :)

  16. [...] Unit Testing iPhone apps with Ruby: rbiphonetest [...]

  17. video on an iphone Sat, 12 Jul 2008 02:05:40 UTC

    [...] hmmm well?? and finally, its the only high-level language you can use to write iphone apps.http://drnicwilliams.com/2008/07/04/unit-testing-iphone-apps-with-ruby-rbiphonetest/macosxhints.com - Watch slow motion video on the iPhone and iPod touch… either on YouTube or your [...]

  18. steve longdo Tue, 22 Jul 2008 11:28:07 UTC

    You can download the SDK (free signup to Apple iPhone Development program: http://developer.apple.com/iphone/program/ ) and compile against the UIKit and CocoaTouch libs. It would be awesome to get Ruby code to simulate gestures, etc.

  19. Thomas Thu, 24 Jul 2008 21:05:11 UTC

    thats pretty cool, thanks for the hint

  20. Matt Sun, 03 Aug 2008 06:06:14 UTC

    Awesome, I look forward to trying it out today at the dev camp.

    (PS: you may want to add this dependency to the gemspec: rubigen) :)

  21. stefan Sat, 09 Aug 2008 21:07:22 UTC

    Hi,

    I really like your testframework!

    Just a quick note:

    It should be [calculator relase]; instead of [calculator dealloc]; in
    - (void) dealloc;

    Cheers,
    Stefan

  22. Rusty Zarse Fri, 15 Aug 2008 21:28:15 UTC

    Thanks for the gem, Dr Nic!
    I am new to mac development, coming (screaming) from a Windows world. I have been slowly dabbling in Ruby and am quite pleased for this business driving opportunity to finally pursue it seriously.

    Finally, I believe “keep your pants on” is derived from “don’t get excited” rather than “don’t get upset” which makes more sense should you imply that before you said topic phrase, we were all so excited we were about to take our pants off. I’ll let you ‘infer’ for what purpose….

  23. [...] God for people like Dr Nic. I managed to test drive a simple calculator project on the iPhone using his screencast. Just a quick note if you don’t come from the Ruby camp, (you know, like you spend most of [...]

  24. Simon T Fri, 24 Oct 2008 23:55:14 UTC

    Nice one Dr Nic, I have been wondering how to get my iPhone app done test first and finally stumbled across your blog…SUBSCRIBED!

  25. Cliff Sun, 02 Nov 2008 11:53:41 UTC

    RSpec? Has RSpec been successfully run on your Ruby iPhone testing framework? I’ve seen bits and pieces of promise from the project page to the email lists but I’d like to see a screencast or some official documentation. I could figure it out eventually, I’m sure but since I’m new to both ObjC and Ruby I’d liet ot hear from the pros. I’m at a point in a project where I could definitely use something like RSpec to describe the screen flow. Tell me there’s a simple solution here, please?

  26. Dr Nic Sun, 02 Nov 2008 13:59:11 UTC

    There shouldn’t be any issues with using rspec vs test/unit. You just need the line that loads the bundle into RubyCocoa (OSX.ns_import :Calculator)

  27. [...] BowlingController as a vanilla NSObject using the “script/generate model” command from Dr. Nic’s RBiPhoneTest. I use rbiPhoneTest to setup the project test structure as well so now I have a rake file in my [...]

Comments