TDD thank-you note

Is TDD worth the effort? Andy Dwelly tried applying my TDD screencasts to his iOS coding. Here’s what he writes in Some notes on Test Driven Development:

At first progress was almost painfully slow.

Yup. It seems like there’s a lot to learn. The real barrier, I think, is that there is a lot to unlearn. And so, when you first get started with Test Driven Development, your productivity will take a big hit. This is normal! But if you’re willing to press through the learning curve, your productivity will increase again — in ways you may not have experienced before…  Continue Reading…

Lock: Sometimes it's OK to unlock for greater testability

Sometimes it’s OK to unlock things for greater testability

In my UIViewController TDD screencast, I put IBOutlets and IBActions in the header file. This made them accessible to unit tests, but I knew it would raise questions:

It’s a fair question. There’s a tension between information hiding (don’t reveal things in the interface) and testability (certain things need to be exposed). Exploring that tension leads me to apply the Extract Class refactoring in places I hadn’t considered before. Continue Reading…


In my screencast of UIViewController TDD, I used an example of incrementing a counter and couldn’t help but give a slight aside: “We’ll increment it… ++count, instead of count++, please.”

I blame Apple for propagating poor incrementing style. Programming with Objective-C starts with the statement, “[Objective-C is] a superset of the C programming language.” But every example they give of incrementing a value uses someInteger++, ignoring the fact that C has two different increment operators!

  • Post-increment: count++
  • Pre-increment: ++count

The Wikipedia article Increment and decrement operators gives clear examples of the difference.

What performance impact will it make? None. The extra code for post-increment semantics is probably optimized away by today’s compilers. Even if it’s not, it’ll still have almost no impact. So what does it matter?

It matters to the reader. It matters because it shows a lack of familiarity with the language’s operators, which doesn’t fill me with confidence in your code. It matters because Objective-C Is Still C (Not Java!)

Say what you mean, rather than relying on side-effects.

This screencast focuses on the question I get the most: “Do you do test-driven development for view controllers?” It’s clearly a roadblock for many people. This screencast should remove that roadblock.

It also answers the question, “Is it worth doing?”

I cover:

  • Three types of unit test verification
  • View controller unit tests: the trick
  • TDD demo
  • How UIViewController TDD can actually help you code faster

Any questions? Continue Reading…

My first screencast! It was sparked by a Stack Overflow question that said, “All the examples of unit testing I read about seem to be extremely simple and trivial.” The question asks how to write unit tests for a piece of sample code. What’s interesting about this problem is that it uses NSUserDefaults.

I cover:

  • What to do with an external object (in this case, the NSUserDefaults singleton). Dependency injection to the rescue!
  • My basic setup: OCUnit + OCHamcrest + OCMockito (along with my test case template and test code snippets)
  • The 3 steps of “The TDD Waltz”
  • We TDD our way to the desired functionality

Any questions? I’d love to hear your experience with this screencast.  Continue Reading…

Code coverage hole

Measure your code coverage to find unit testing holes

Update: For Xcode 5.1, see Code Coverage Fixed for Xcode 5.1

One of the first things I do when working on any Xcode project is set up code coverage. If the coverage shows a hole, I know that area is lacking unit tests.

(Be careful, the opposite isn’t true: Just because some code has been touched by unit test execution doesn’t mean it’s actually covered. If altering the behavior of the code causes a test to fail, then you know it’s covered.)

Many people use CoverStory, a a code coverage browser app written by my friend Dave MacLachlan. Others use gcovr to integrate code coverage into their Jenkins continuous integration. Me, I use lcov because it lets me exclude third-party libraries from the measurements before generating an HTML report. Continue Reading…

Test-Driven iOS DevelopmentMany programmers assume that Test Driven Development doesn’t work well for iOS development. This ill-founded assumption really comes from a lack of any experience with TDD. But because iOS developers learn most of their chops by referring to other people’s code, it also comes from a lack of helpful examples.  So I was really glad when Graham Lee’s book Test-Driven iOS Development came out. Finally, something I can point others to besides my code!

Book overview

Chapter 1 starts off with a surprising answer to the question, “Why write unit tests?” Why, to make more money! It shows how the traditional handoff-to-QA form of testing comes from the waterfall model of development, and how the cost of fixing defects increases with each phase of the waterfall.

Chapter 2 lays out the principles of Test Driven Development: test first, writing “Just Barely Good Enough” code that satisfies the test, and refactoring. But it also describes an important principle from Extreme Programming: “Ya Ain’t Gonna Need It,” or YAGNI. Basically, code only what you need to. This keeps production code simple, and avoids wasting time writing code that won’t have any effect.

The book goes on to introduce unit testing by showing how one might write tests without a unit testing framework — the old-fashioned way! Then we get an overview of the more common tools. Finally, we hit the meat of the book: a full example of creating an iOS app using TDD, spanning five chapters. Continue Reading…

"The Self-Talk Solution" for Objective-C init is simple: avoid it

Avoid self-talk in Objective-C init methods!

[This post is part of the Code Smells in Objective-C series.]

Here’s something I see a fair bit in code for Objective-C init and dealloc. I’ll give a simple example. Can you tell what’s wrong?

- (id)initWithFoo:(id)foo
    self = [super init];
    if (self)
        self.something = foo;
    return self;

- (void)dealloc
    self.something = nil;
    [super dealloc];

Hint: It’s those self-dots. They have a tendency to lull people into thinking they’re simple assignments. But remember, dot notation conceals messaging.

Let’s avoid dot notation and try again: Continue Reading…

Dot notation: 100% PURE EVIL

Dot notation: 100% PURE EVIL

[This post is part of the Code Smells in Objective-C series.]

Dot notation for messaging isn’t just an Objective-C code smell. It’s evil, I tell you!

Update: I recently changed my mind! See my post In Which I Embrace Dot Notation…

…OK, so that’s hyperbole. I do manage to coexist with dot notation in projects that have it. But I won’t write it myself. Here are 3 reasons I avoid dot notation in my code: Continue Reading…


Over-relying on precompiled headers can cripple your code!

[This post is part of the Code Smells in Objective-C series.]

Precompiled headers were invented for one purpose: to make compiling faster. Rather than parsing the same header files over and over, these files get parsed once, ahead of time. Speed is important! The faster you compile, the faster you can complete the feedback loop to see if recent changes were successful.

In Xcode, you do this by including the header files you want in a “prefix header,” and enabling “Precompile Prefix Header” so they get precompiled. But the idea behind a prefix header is different from precompiling. A prefix header is implicitly included at the start of every source file. For example, if your prefix header is Prefix.pch, it’s like each source file sneaks

#import "Prefix.pch"

at the top of the file, before anything else. This can be handy for project-wide #defines. (Just remember that in general, #defines are a code smell.)

It’s also handy for precompiled headers. The fact that every source file includes these precompiled headers is an artifact of being in the prefix header.

And this is where things start to go wrong… Continue Reading…