In the Objective-C community there are several frameworks, that at the surface, offered the BDD style I was looking for:
- Kiwi – “Simple BDD for iOS”
- Cedar – “BDD style testing for Objective-C”
- Specta – “A light-weight TDD / BDD framework for Objective-C & Cocoa”
All three have similar features and support the style you would expect. Here is an example of using Specta to describe an objects behavior:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
After playing with each of the three I decided to go with Specta and have been really happy with that choice. My criteria was based on:
- The ability to easily add the framework to an existing XCode project.
- The ability to write asynchronous test cases. Often I’d need to test objects that take block arguments for callbacks – this was a must.
- Integration into other mainstream tools. XCTool and XCode are well supported with Specta.
- A good project “pulse” on GitHub.
1 2 3 4
The Specta project came to the rescue again with Expecta. It has proven to work well and provides a lot of features:
- A good set of built-in matchers
- The ability to define your own matchers
- Dynamic predicate matchers. Being able to write something like
expect(lightSwitch).isTurnedOn();with minimal effort is great.
- Testing framework agnostic. Expecta will work with not just Specta but other testing frameworks.
- A good project “pulse” on GitHub
In unit testing I often make use of an Isolation Library. While these are often referred to as Mock libraries, it’s really just a library for making fake objects on the fly. I primarily need Mock and Stub objects and so far I’ve been using OCMock with good success.
Often with fake objects you want to create Stub objects that are not “strict” – meaning they don’t complain if methods you didn’t explicitly setup are called. One bummer is that with OCMock you must remember to create a “Nice Mock” in order to get that behavior:
Argument constraints are another important feature for Mock objects. OCMock has a decent set of built-in argument constraints, and when the built-in constraints won’t cut it you can reach for a custom predicate constraint via a block you implement:
1 2 3
This actually turns out to be the way you can mock calls of methods that take block arguments. In a recent project we had an API Client object that used AFNetworking to implement it’s HTTP communication. Each method call would take a callback for when that communication completed. For unit tests that needed to Stub or Mock this interaction I used the following approach:
1 2 3 4 5 6 7 8 9 10
Mock objects are always “nice,” recording their calls instead of throwing exceptions about unspecified invocations. This makes tests less fragile.
No expect-run-verify, making tests more readable. Mock objects record their calls, then you verify the methods you want.
Verification failures are reported as unit test failures, identifying specific lines instead of throwing exceptions. This makes it easier to identify failures.
Writing tests is important, but equally important is running those tests to get feedback and to quickly iterate during development. For running tests I’ve been making heavy use of XCTool. XCTool is a tool for building and testing your application at the command line. This was big not only for those who prefer that local development environment but for running the tests during Continuous Integration on a remote server.
One thing I quickly added to our project was XCTool’s ability to have default arguments passed to the command by having a
.xctool-args file in the root of your project.
1 2 3 4 5 6 7
With that you can easily run your tests by running
Better yet – for those who like to practice TDD you can combine XCTool with the power of Guard so that you tests will automatically run when you make changes to any of your project source files. An easy way to get started with this is to use the guar-xctool-test gem from Francis Chong.
The tools you use are really a personal preference – These are mine. As I’m sure you already know these are not the only options out there. I encourage you to find the tools that make you productive and happy.