Adam Milligan's blog
As I wrote here we've used OCHamcrest matchers for some time for writing expectations in Cedar, but have found them unsatisfying. We wanted convenient matchers, like the ones Jasmine provides for JavaScript, but for Objective C. To that end, we added Cedar-specific expectation functions and matchers that specifically solve the problems we had with OCHamcrest.
To use Cedar's expectations you need to make a couple small changes to your spec files:
1) Cedar matchers use C++ templates. Tell the compiler to expect some C++ code by changing the file extension on your spec files from .m to .mm.
2) Cedar matchers live in a C++ namespace. At the top of your spec file, after the includes, add this line:
using namespace Cedar::Matchers;
At Pivotal we write a lot of tests, or specs if you prefer. We TDD nearly everything we write, in every language we write in and on every platform we write for, so we actively work to improve every aspect of our testing tools. Personally, as I've written tests in Objective C I've found that the syntax of expectations has left much to be desired.
Like many people who write Objective C, I've spent a fair bit of time with languages like Ruby and JavaScript. When I write specs I often yearn for the simplicity of the expectation syntax in those languages. For example, some simple expectations in JavaScript, using Jasmine:
expect(composer.name).toEqual("Ludwig");
expect(composer.symphonies.count).toEqual(9);
expect(composer.symphonies).toContain("Eroica");
expect(composer.symphonies).not.toContain("Appassionata");
In comparison, the same expectations in Objective C, using OCHamcrest:
assertThat(composer.name, equalTo(@"Ludwig"));
assertThatUnsignedInt([composer.symphonies count], equalToUnsignedInt(9u));
assertThat(composer.symphonies, hasItem(@"Eroica"));
assertThat(composer.symphonies, isNot(hasItem(@"Appassionata"));
Thanks to Sean Moon and Sam Coward Cedar now has colorized output on the command line:

If you'd like to display colorized output like this you can specify the appropriate custom reporter class using the CEDAR_REPORTER_CLASS environment variable. We do this in our Rakefiles, like so:
task :specs => :build_specs do ENV["DYLD_FRAMEWORK_PATH"] = BUILD_DIR ENV["CEDAR_REPORTER_CLASS"] = "CDRColorizedReporter" system_or_exit(File.join(BUILD_DIR, SPECS_TARGET_NAME)) end
You can set the environment variable in whatever way works for you. You can also set it to any reporter class you choose, so customize away.
Apple's inclusion of the UI Automation component in Instruments with iOS 4 is a definite step in the right direction. It's the first reasonable way to write tests that externally exercise your actual app, rather than weirdly injecting test code into it. It's also the only way to programmatically test lifecycle issues, such as how your app behaves when put in the background, when rotated, when the device locks, etc. Good stuff. Unfortunately, the current implementation of UI Automation also has some significant problems:
- There's no way to run tests from the command line. The subtitle of the WWDC talk for UI Automation was "find bugs while you sleep;" unfortunately, you can't find bugs while you sleep if you have to wake up to click the "Run" button.
- There's no way to set up or reset state. The lack of fixtures which set up a known state at the beginning of iPhone tests has been a problem for unit testing (with OCUnit, Cedar, or what have you), particularly for apps that use CoreData. Now it's worse than ever, because UI Automation manipulates the actual state of the app on the device, much like Selenium does in a browser. Sadly, UI Automation provides no method for reseting the device's state, making it nigh impossible to prevent tests from affecting one another.
- Part of the previous problem is that UI Automation has no concept of discrete tests; it provides no form of organization for your test scripts. No test methods, no set up or tear down methods, just one big stream of consciousness line of execution. Obviously you can break this up into functions as you see fit, but why reinvent the wheel? Since the test script is JavaScript, I like the idea of using Jasmine for this.
- There's no way to programmatically retrieve the results of the test run. You could debate the value of solving this issue at the moment, considering there's no way to programmatically start the tests either. However, even if you were to write some clever AppleScript to kick off the tests automatically the only indication of the pass/fail status is in the Instruments UI, so you still have to wake up to check the results. I searched around a bit for information on deconstructing the protocol that UI Automation uses to talk to the device, but I came up empty.
I'll definitely use UI Automation, particularly for app lifecycle testing. But, not being able to add those tests to a CI build definitely stings. I very much hope Apple keeps their momentum for automated testing and makes it more developer-friendly.
Since the language of the new iPhone UI Automation component is JavaScript I figured the easiest way to organize tests is to use a JavaScript testing framework, such as Jasmine. So, I created jasmine-iphone, which is little more than a few simple scripts to make UI Automation and Jasmine play nice.
Once you clone jasmine-iphone from GitHub (it includes Jasmine as a submodule, so be sure to git submodule init && git submodule update) you can copy the example-suite.js file, import your spec files, point Instruments at your suite.js and go.
As an example, I set up a trivial example in the Cedar project. The directory structure looks like this:
Project Directory
\- Spec
\- UIAutomation
\- jasmine-iphone <--- submodule
\- jasmine <--- nested submodule
\- suite.js
\- thing-spec.js
\- other-thing-spec.js
The suite.js file is relatively simple (note that I moved it up one directory from where the example-suite.js file is, so the #import statements are slightly different):
#import "jasmine-iphone/jasmine-uiautomation.js" #import "jasmine-iphone/jasmine-uiautomation-reporter.js" // Import your JS spec files here. #import "thing-spec.js" #import "other-thing-spec.js" jasmine.getEnv().addReporter(new jasmine.UIAutomation.Reporter()); jasmine.getEnv().execute();
You can write the specs themselves the same way you'd write Jasmine specs for anything else. The UIAutomation subclass of the Jasmine Reporter takes care of marking the start of each spec, as well as reporting if it passes or fails. You'll need to use the UIAutomation classes and methods for driving your application's state, of course.
That's it. Try it out and see what you think.
If you're interested in following the growth of Cedar, or just testing iPhone projects in general, you can join the public Cedar discussion group or follow Cedar on Twitter at @cedarbdd.
I'll continue to write out my thoughts on the topic here, but I'd prefer to have a method of sharing information that anyone can post to.
When I started writing Objective-C for iPhone and iPad projects I started to hear about these mystical and all-powerful run loops objects. Everything seems to relate to run loops, all the class references talk about how one object or another depends on run loops, the most basic iPhone application documentation even talks about how the device starts and maintains the main run loop for you because it's so important. However, I found few straightforward descriptions of what a run loop is or how it works.
So, I read Apple's Threading Programming Guide. I read about timers and ports and sources, about the starting and stopping and timing out of run loops. After this reading, and a bit of thought, I realized that all the sound and fury surrounding run loops blinded me to the fact that they are actually very, very simple. To wit, run loops are a mechanism for single-threaded asynchronous programming. Sound familiar? Sounds to me a lot like JavaScript.
A little while ago I wrote about Cedar, a BDD-style testing framework for Objective-C. The responses I received nearly all went something along these lines: "That's great! Too bad I can't use it, since I'm writing an iPhone app."
Hogwash.
I actually wrote Cedar specifically for testing iPhone OS projects we're working on at Pivotal. To prove it, I've started a small public iPhone project that I've test-driven entirely with Cedar. You can get the project here (more on that in a bit); it should eventually allow you to log into Pivotal Tracker, see all the delivered stories in a given project, and accept or reject each one. At the moment it does little more than start up and display the Pivotal Chicken*, but it does contain Cedar specs that run on and off the device.
As we've grown our mobile practice at Pivotal we've tried to apply to it the same principles and disciplines that have made our Rails practice successful. Often the one that we have the most difficulty translating is testing. In my experience the testing tools for Objective-C in particular are significantly wanting; there are some out there, but they're hard to find, often hard to use, and occasionally defective in frustrating ways.
One of the things I found I miss most in testing Objective-C, Java, or C++, is the hierarchical structure for organizing tests that frameworks like RSpec or Jasmine provide. I find nested describes indispensable for managing orthogonal aspects of the classes under test, for handling preconditions, for eliminating redundant setup code, and for generally keeping my sanity. So, when I first heard about the addition of blocks in the GCC compiler for Objective-C the first application that came to mind was testing.
So, I wrote Cedar, a BDD-style framework for writing tests in Objective-C. The code is available here. Perhaps more importantly, Cedar is in its infancy so I'm interested in any suggestions and feedback. To that end, I created a public Tracker project for it here.
Years ago, after I finished college but before I started working professionally with software, I spent a couple years working as a paramedic. I learned a lot from that job, not least about interacting with people who really, really don't want you in their lives.
One of the calls I remember most vividly happened around three in the morning, not long after schools had let out for the summer. A group of recently graduated high school girls had rolled their Ford Bronco on the highway. When we arrived an engine company was on scene, busily cutting the remains of the car into fun size Bronco strips. I followed the trajectory implied by the hole in the windshield and found my patient, the driver, on the pavement some distance from the car.
