Today was the first day that Test Driven Development actually justified its existence

I’ve been making apps since iOS 2.2.  People tell me I’m good at it.  Meh.  There’s always a bigger fish.  I love what I do, so chances are I’m not horrible at what I do.

Today was the first day where I used Test Driven Development to actually develop code.  Don’t get me wrong; it’s not like I don’t write unit tests.  I do.  But what I’m referring to right now is where you actually are given the start and passing conditions of a test before there is any code written at all.  In my field of work, this never happens.  The design is ALWAYS a moving target.  Nothing in the startup world is ever known in advance, so although you could write unit tests, it doesn’t always make sense.

I’ve recently been working on the implementation of the rules of Canadian Ice Hockey.  (Don’t ask.)  The sport itself seems pretty straightforward.  Put the puck in the net.  Goal.  Increase Score.  No way!  There are a lot of complicated rules surrounding penalties, but thankfully there is a referee’s handbook that goes over all the complicated scenarios and tells you what the result should be.

Perfect for TDD.  I literally wrote all the unit tests before I wrote the code that would produce the expected results.  I love it because I have to be honest; the solver code I wrote just “feels bad”.  I’m not even certain how parts of it work, and I only wrote it this past week.

What unit tests tell me is: It doesn’t matter!  As long as the tests pass, the code does what it’s supposed to do.  Very satisfying.

 

Advertisements

On the Separation of QA from Development

I don’t know maybe it’s just me, but it’s very important for me to be able to be “in the zone” when I’m programming.  If I’m in the zone, I feel superhuman and am able to accomplish the work of 2 or more people at once.  Being in the zone, in computer techie parlance, is like having a large store of volatile RAM completely loaded with all the information you’re working on trying to solve the problem.  Any time someone turns up to distract you, it’s like they’ve just pulled the plug on your computer.  Now you have to boot back up, load all the data, re-orient yourself with the task, then continue working.  Until the next distraction.

I notice I get extremely hostile when this continues to happen on any given day.  I request home office time a lot, not because I don’t like my co-workers or my work environment, quite the opposite actually, it’s just that I love being in the zone and know that it’s also good for me to be there from a business perspective.

We’re now going through a small QA cycle and so of course there will be bug reports.  What I’ve come to realise is that it’s important to keep testers away from developers.  Because testers will find a bug and feel that they need to tell you about it right away.  But, as mentioned before, they pull the plug each time they do so, then of course probably don’t understand why I slowly want to rip their head off.  “Dude, what’s your problem?”….

Well, here is my problem.  I just explained it.  Use Trello.  Put it on a card list.  Let me get to it asynchronously.  It’s better for everyone that way.  If I need clarification, I will come find you.  Not in any elitist sense, but purely business – my time is worth more than yours.   It’s best to prioritise my efficiency over yours.

Unit Testing Block-based APIs

UPDATE:  I’ve changed my answer now.  The Original Post (marked as such below), represents the solution called “spinlock”.  It’s undesirable.  Have a look at this post on Grand Central Dispatch over at www.raywenderlich.com under the section “Semaphores”

The updated solution, which achieves the same result only better, can be done using a new XCTestCase baseclass for your test cases:

#import <XCTest/XCTest.h>

@interface HSAsynchronousTestCase : XCTestCase
{
   dispatch_semaphore_t _waitSemaphore;
}
- (void)HS_beginAsyncTest;
- (void)HS_completeAsyncTest;
- (void)HS_waitToComplete:(NSTimeInterval)timeoutDuration;

@end
 

@implementation HSAsynchronousTestCase

- (void)HS_beginAsyncTest
{
    _waitSemaphore = dispatch_semaphore_create(0);
}

- (void)HS_completeAsyncTest
{
    if (_waitSemaphore) {
        dispatch_semaphore_signal(_waitSemaphore);
        _waitSemaphore = nil;
    }
    
}

- (void)HS_waitToComplete:(NSTimeInterval)timeoutDuration
{
    dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t) (timeoutDuration * NSEC_PER_SEC));
    if (dispatch_semaphore_wait(_waitSemaphore, timeoutTime)) {
        XCTFail(@"Test timed out");
    }
}

- (void)setUp
{
    [super setUp];
    [self HS_completeAsyncTest]; // in case something went wrong with the last one...
}

@end

 

Then you use it analogously to the code below.  Where the _done = YES; calls are [self HS_completeAsyncTest]; and _done = NO; are the [self HS_beginAsyncTest];.

One more time, you call [self HS_beginAsyncTest]; before your asynchronous method, you call [self HS_completeAsyncTest]; in the completion block(s) of that method, and you call [self HS_waitToComplete: kSomeDurationInSeconds]; at the end of your method.

ORIGINAL POST for Reference

This is a code recipe that I’ve been using for a while and I’m sad to say I’m not even sure who I got it from. Obviously a wonderful person on stackoverflow.com.

I’m putting here for my own purposes as I tend to refer to my own posts at times. “How did I do that again…?”

The problem with any asynchronously executed code is that it finishes after the calling method does. So the method returns before your test is truly finished. We need to stop that method from returning until the asynchronously executed stuff has returned its result. This is how you do it.

Say you have a Unit Test Case subclass

@implementation SomeModel_Tests
{
    __block BOOL _done;  // add a block variable
}

/**
Then add this helper method
*/
- (BOOL)waitForCompletion:(NSTimeInterval)timeoutSecs
{
    NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeoutSecs];
    NSLog(@"Wanting to wait on thread %@", [NSThread currentThread]);
    do
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeoutDate];
        if ([timeoutDate timeIntervalSinceNow] < 0.0)
        {
            NSLog(@"Breaking out of waitForCompletion!");
            break;
        }
    }
    while (!_done);
    return _done;
}

// ...
@end

Now we have everything we need to test a block-based API. For example:

- (void)testSomeParsingOperation
{    
    NSURL *contentURL;
    contentURL = [NSURL URLWithString:@"http://www.someurl.com/content.json"];
    NSURLRequest *request = [NSURLRequest contentURL];
    
    JSONParsingRequestOperation *op;  // I just made this up.
    op = [JSONParsingRequestOperation JSONRequestWithRequest:request
                                             completionBlock:^(BOOL success, NSSet *parsedDataObjects, NSError *error)
    {
        XCTAssertTrue(error == nil, @"Parsing should have worked!");
        XCTAssertTrue(parsedDataObjects.count > 0, @"Because I know content.json should have objects in it");
        _done = YES;
    }];
    
    [[AFHTTPClient sharedClient] enqueueHTTPRequestOperation: op];
    
    [self waitForCompletion: 260];
}

That’s it. Have fun.

Updated some info about Mantle

I haven’t been blogging too much recently. My bad. In the meantime I’ve been working on my own App, a Songbook App that allows MIDI control so that if you want to change pages and your hands are busy playing instruments, you can use something like a footswitch controller to change the page.

Check out my Portfolio page for that.

If you’re not a music person, here’s a quick post to tell you that I updated my post about the Mantle Framework. It discusses some findings about working with primitives in your data models, something that wasn’t quite clear to me. In short, Mantle is awesome and does that all for you.

Recipe: a Podfile with different Pods per target

So, say you want to have specific pods for unit testing. You wouldn’t want to include those in your main target, now would you?? Of course not! So, here’s a quick recipe so you can see how you would set that up in your Podfile.

Also assuming you checked the box ‘Include Unit Tests’ when you set up your Xcode project. Otherwise, see here

If the name of your app Target is MyGreatApp and your unit testing target is: MyGreatAppTests

platform :ios, "5.0"  #or whichever you need to support.  Your deployment target

pod "DCIntrospect"  # most awesome tool
pod "AFNetworking", "~>1.3.2"  # a standard lib iOS apps
pod "SSZipArchive"  # zipping/unzipping anyone?
pod "MD5Digest"   # don't let your filepaths be corrupted by newlines and spaces again.  
pod "MGImageUtilities"  #don't cache images for UIImageViews with fixed frames using a UIViewContentModeScaleAspectFi... resize and cache those

target :test, :exclusive => true do
    link_with 'MyGreatAppTests' #i.e. the test target name in your project
    
    pod 'OCMock', '~> 2.1.1'  #OCMock.  Great helper
    pod 'Expecta', '~> 0.2.1'  #nice syntax.  you can write readable pass conditions.

end

Cocos2D Revised Template – Easy-ARC, Unit Tests, Cross-Ref’d Source

I don’t know about you guys, but on the one hand I’m grateful for all the people who make it easy to get up and running with either a UIKit based project or a Cocos2D based project in Xcode. Because I’ve just spent literally hours ripping my hair out in frustration, stuck on configuration details and so on. I hate that; trying to fumble through a task, really not knowing what causes it to fail and in the end you get it working and really not know why it did stop failing. (Talk about a cry for mentor help!)

So, this is what I want to do:

* I want the functionality of a Cocos2D template, but I want to cross-reference the Cocos2D-iOS project and not have the source there already (i.e. if I wanna update my source, it should be easy)

* I want it set up for ARC

* I want to have unit tests

Unfortunately the current templates don’t provide this. So, here’s how I got it working:

* Create a new Project, using the Cocos2D iOS Template

* Now go to the App Target’s Build Settings and notice what might be interesting here (in the event you wanted to work without templates):
– Other Linker Flags (-lz -ObjC)
– Location of the Info.plist file
– Header Search Paths (where to locate the kazmath headers)
– Location of Prefix Header
– Preprocessor Macros

* Double check some Project Build settings
– iOS Deployment target (could be 5.0 at this point)
– Objective-C Automatic Reference Counting should be set to YES, and make sure this is also the case in your App Target

* We will now delete the libs folder from the Project and send it to the Trash, but before that, notice what libs are in there: cocos2D, cocosDenshion, and kazmath. Ultimately these are the ones that our project will depend on. Now delete that libs folder and send to trash.

* Now we want to cross-reference the cocos2D source, so that it can be managed separately from our App’s code. The way I like to do this now is with git submodules (as I don’t write any code without it being in a git repository, local or remote, as long as there’s some source control!) So for that we go to the command line in the root of our project and type:

git submodule add https://github.com/cocos2d/cocos2d-iphone.git cocos2d_src

Which will clone that repo into this repo, and put it in the folder called cocos2d_src.

(At this point you may want to create an appropriate .gitignore file for your repo if you haven’t done so already – github provides a decent one for Objective-C or see the bottom of this post for something you can copy-paste)

* Now, in that cocos2d_src (once it’s finished downloading!) folder, drag the cocos2d-ios.xcodeproj file into your project, thereby creating a cross-project reference. Another reason why cross-project references are good is that they compile separately, which means we don’t care if that project is ARC or not, because it gets compiled separately. We want ARC, so it’s good to keep cocos2D source out of our Project’s source, so you don’t have to turn on ARC for half of your project, and off for the other half.  Let them compile separately.

* Now we need to be able to work with that source. As I mentioned, we need to be able to use cocos2D, cocosDenshion, and kazmath. In your PROJECT‘s (You put it in the project’s settings to that the unit tests will also have access to them… does anyone know a ‘cleaner’ way to do this?) build settings, go to Header Search Paths and add 3 entries:

$(SRCROOT)/cocos2d_src/cocos2d                          (recursive)
$(SRCROOT)/cocos2d_src/external/kazmath                 (recursive)
$(SRCROOT)/cocos2d_src/cocosDenshion/cocosDenshion      (recursive)

The next step is to set up the dependencies to this other project. In your Build Phases, add target dependencies to cocos2d, CocosDenshion, and kazmath. In Link Binary With Libaries, add libcocos2d.a, libCocosDenshion.a, and libkazmath.a

Now, in your Project’s Precompiled Header file (Prefix.pch), add #import “cocos2d.h” underneath the UIKit and Foundation framework imports. For those of you a bit new to this, this is a way of saying “make this framework available everywhere, as if I import this in each header file I make”. It’s also a quick check to see if everything has worked so far. Build and run the project and hope it succeeds.

If yes, then great. If not… Oh yeah, you’ll get errors due to ARC being enabled and some code is non-ARC. Either delete the HelloWorldLayer and Intro Layer classes from your project, or remove all lines of code with “release” statements, and remove all dealloc method implementations. Then you also have to update your main.m file as it uses new syntax regarding Autorelease pools:

– replace old non-ARC main.m implementation with ARC main.m implementation:

int main(int argc, char *argv[]) {
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, @"AppController");
  }
}

Otherwise if it still doesn’t work… hmm… double check the steps above? Don’t you just hate those tutorials when it doesn’t work as written?

Now then, this is Checkpoint ONE of the tutorial. Now we have an ARC-ready project that uses Cocos2D source that you can keep up-to-date as it’s checked out from the github repository. Convenient!

Next, onto adding Unit Testing. The next bit was inspired by this post, summarised below:

* Click on your Project to get to its settings -> Add Target -> iOS -> Cocoa Unit Testing Bundle
* Name the new target something appropriate -> “MyAppTests”
* Go to the Build Phases tab of your UNIT TEST target, and create a dependency to your App Target
* Under Build Settings, set Bundle Loader to:

$(BUILT_PRODUCTS_DIR)/MyExistingApp.app/MyExistingApp

* Set the Test Host to

$(BUNDLE_LOADER)

* Go back to your APP TARGET, and set Symbols Hidden by Default to NO

In addition, you may want to set your UNIT TEST target’s pre-compiled header .pch file to be the same as your App Target, but that’s up to you and your desired configuration.

So, if everything’s gone right, you’re up and running and good to go! You may want to commit this to a repo with a specific tag, so you can check that out in the future and save yourself some time.

BONUS:

You could add ChipmunkPro to your project, if you do it’s pretty straightforward.  Import the folder into your project (with static lib .a file) and add ObjectiveChipmunk.h to your .pch file.  Ooops, but it won’t compile!  You have to link the ImageIO.framework to your project.

EXTRA AWESOME TIP: Use the following as your .gitignore file BEFORE you do any commits!!! Otherwise it’s a pain in the ass for the git beginner to deal with it later, especially when switching branches and dealing with Xcode files…

# Xcode
*/build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
*.moved-aside
DerivedData
.idea/
*.hmap

#Xcode files
#This ignores everything inside a *.xcodeproj except the project.pbxproj
*.xcodeproj/
!*.xcodeproj/project.pbxproj
*.log

# OSX Noise
.DS_Store
profile
*~
*.lock
*.DS_Store
*.swp
*.out