You must fail before you can succeed!


If you try to fail and you succeed, which have you actually done? Are you a success? Or a failure? Is it good to be a failure? Is it better to be successful at failure? Let’s add detail to the question. By the way, I’m Cliff. You’re here because you tried to fail and you succeeded. Today’s topic is something I’ve visited before. It’s a new thing I’m trying with unit tests. Actually it’s an old thing to many but I’m trying it for the first time in both C++ and ObjC so it feels sorta new-ish.

How do you unit test?
Let’s start with how you unit test. What are your steps? What are the recommended steps? In order to be successful at TDD you must appreciate the entirety of the practice. It goes, “Red, Green, Refactor”. Red comes before Green, just like with traffic lights. What I’m saying is that you have to begin with a failing test. The first test is important. The first failure should describe what work you have to do. In my case, I’m swimming in un-ventured waters (C++/ObjC++ testing) so there’s some learning that needs to be re-enforced. Here’s how I’ve been starting my tests recently:

//
//  MyCoolNewObjectTest.m
//  Created by cliftoncraig07 on 12/1/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
#include "MyCoolNewObject.h"

@interface MyCoolNewObjectTest : SenTestCase
{
  MyCoolNewObject *coolObject;
}
@end

@implementation MyCoolNewObjectTest

-(void) setUp
{}

@end

The test shell is completely empty except for references to the “thing” I’m about to create. I get my first failure which is a compile error stating that this thing does not exist. “No such file error…” around the include. Here I have an opportunity to review my design as minimalist as it is. I ask, “Does the error make sense? Is it expected? Do I like the name of this cool new thing I’m creating? Is it specific to the task I’m assigned to?” Always review each error with these question. After creating the files for the new “thing” I then follow up with:

//
//  MyCoolNewObjectTest.m
//  Created by cliftoncraig07 on 12/1/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
#include "MyCoolNewObject.h"

@interface MyCoolNewObjectTest : SenTestCase
{
  MyCoolNewObject *coolObject;
}
@end

@implementation MyCoolNewObjectTest

-(void) setUp
{ STFail(@"You must fail before you can succeed!"); }

@end

Also important, while I train myself on the new testing framework, because I need to catch myself misnaming the “setup” method which should have a capital “U”. It also lets me know that my test is actually running as part of the suite. Far too often, in Xcode, I’ll have the wrong target active and begin writing the wrong code because I was getting false positives from tests that were never run. Here’s where it gets interesting. The STFail in the above example does not fail! Now we face our original question, if you try to fail, as we have above, and you succeed like our test suite will do here, which have you actually done? The first time I hit the unexpected success I got nervous and read all around the SenTesting framework and OCUnit. Eventually I settled on the conclusion that because there were no tests to run the setUp was being optimized away as unnecessary. What the above example is pointing out is that such a test case can never fail since there are no tests. That leads us to our final step…

//
//  MyCoolNewObjectTest.m
//  Created by cliftoncraig07 on 12/1/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//
#import <SenTestingKit/SenTestingKit.h>
#include "MyCoolNewObject.h"

@interface MyCoolNewObjectTest : SenTestCase
{
  MyCoolNewObject *coolObject;
}
@end

@implementation MyCoolNewObjectTest

-(void) setUp
{ STFail(@"You must fail before you can succeed!"); }

-(void) testSomething
{}

@end

…and here we get our familiar red bar! Our test case is complete and we now understand a little more about OCUnit. That’s it for today. Go on. Nothing else to see here. I know what you’re thinking. “We haven’t written or learned anything new!” Sure we have! We’ve written and validated our first test case in ObjC++. (I’m using OCUnit w/ C++ extensions to exercise or test drive C++ code.) The little amount we went over here is persistent through all the testing you will do from then on. It starts from the basic mechanics. Make sure every line of code is proceeded by some test (or compiler) failure. If you’ve done more than 2-3 things and haven’t run a build to generate a failure then you’re completely off track.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 251 other followers

%d bloggers like this: