Thursday
05Nov2009

Asynchronous unit testing with OCMock

I've recently been using OCMock more and more. It's a great mocking framework for writing unit test for the mac or the iPhone.

When I mock delegate objects which wait for asynchronous callbacks I use this handy utility method

Update

There was a bug in here which made the utility return early, no matter how long the delay was. I've updated the code to fix the bug.

//
//  TestUtils.h
//
//  Created by Hans Sjunnesson on 2009-11-05.
//

#import <Foundation/Foundation.h>
#import <OCMock/OCMock.h>

@interface TestUtils : NSObject {

}

/*!
 @method waitForVerifiedMock:delay:
 @abstract Runs the current run loop for as long as specified by the delay, or until the mockobject verifies.
 @param mock the OCMockObject to verify.
 @param delay the time to wait until the mock is verified, in seconds.
*/
+ (void)waitForVerifiedMock:(OCMockObject *)mock delay:(NSTimeInterval)delay;

@end

And the implementation:

//
//  TestUtils.m
//
//  Created by Hans Sjunnesson on 2009-11-05.
//

#import "TestUtils.h"


@implementation TestUtils

+ (void)waitForVerifiedMock:(OCMockObject *)inMock delay:(NSTimeInterval)inDelay
{
  NSTimeInterval i = 0;
  while (i < inDelay)
  {
    @try
    {
      [inMock verify];
      break;
    }
    @catch (NSException *e) {}
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5]];
    i+=0.5;
  }
}

@end

Here's an example of testing 'NSURLConnection' trying to connect to google.com.

@implementation NSObject (NSURLConnectionDelegate)
  - (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {}
@end

- (void)testShouldConnect {
  id mock = [OCMockObject mockForClass:[NSObject class]];

  NSURL *url = [NSURL URLWithString:@"http://www.google.com"];
  NSURLRequest *request = [NSURLRequest requestWithURL:url];
  NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:mock startImmediately:NO];
  [[mock expect] connection:connection didReceiveResponse:OCMOCK_ANY];

  [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
  [connection start];

  // Wait for five seconds
  [TestUtils waitForVerifiedMock:mock delay:5.0];

  STAssertNoThrow([mock verify], @"Should be able to connect to google.");
}
Sunday
25Oct2009

Turn Core Data models into JSON

Json is a lightweight data-interchange format, says the official website. Think XML but with a format that's easier for both people and javascript interpreters to parse. Here's an easy way to serialize Core Data models into json.

First, download blakeseely's bsjonadditions project and include the source in your xcode project. Secondly, copy & paste the following snippet into a new file in your project called NSManagedObjectExtras.m:

//
//  NSManagedObjectExtras.m
//

#import "NSDictionary+BSJSONAdditions.h"
#import "NSArray+BSJSONAdditions.h"


@implementation NSManagedObject (NSObject)

- (NSDictionary *)propertiesDictionary
{
  NSMutableDictionary *properties = [[[NSMutableDictionary alloc] init] autorelease];

  for (id property in [[self entity] properties])
  {
    if ([property isKindOfClass:[NSAttributeDescription class]])
    {
      NSAttributeDescription *attributeDescription = (NSAttributeDescription *)property;
      NSString *name = [attributeDescription name];
      [properties setValue:[self valueForKey:name] forKey:name];
    }

    if ([property isKindOfClass:[NSRelationshipDescription class]])
    {
      NSRelationshipDescription *relationshipDescription = (NSRelationshipDescription *)property;
      NSString *name = [relationshipDescription name];

      if ([relationshipDescription isToMany])
      {
        NSMutableArray *arr = [properties valueForKey:name];
        if (!arr)
        {
          arr = [[[NSMutableArray alloc] init] autorelease];
          [properties setValue:arr forKey:name];
        }

        for (NSManagedObject *o in [self mutableSetValueForKey:name])
          [arr addObject:[o propertiesDictionary]];
      }
      else
      {
        NSManagedObject *o = [self valueForKey:name];
        [properties setValue:[o propertiesDictionary] forKey:name];
      }
    }
  }

  return properties;
}  

- (NSString *)jsonStringValue
{
  return [[self propertiesDictionary] jsonStringValue];
}

@end

Now all you need to do is to call [coreDataModel jsonStringValue] to get the model as a json string.

Tuesday
04Aug2009

Anthony Burch rants on indie games

I'm dizzy from nodding in agreement with this video rant from Anthony Burch. He touches on the state of big-media games, with massive budgets and marketing vs. independently created, small games.

One of the point he makes is how consumers willingly fork over sixty bucks for a pile of crap, while independent game makers put out wonderfully moving pieces such as "Today I Die" and "Passage" and are having a hard time scraping by on donations.

Watch the video, take some time to play the games that Burch talks about and if you enjoy them, donate a few bucks for the good cause.

Saturday
25Apr2009

A simple multipart/x-mixed-replace HTTP test-server

I've recently fiddled around with streaming HTTP connections. I needed to make a client which interfaces with an HTTP server that streams data via Content-type: multipart/x-mixed-replace.

Unfortunately NSURLConnection turned out to handle multipart/x-mixed-replace really poorly. More on that later though. For now I just wanted to share a simple ruby script I created to test my client.

The script serves multipart/x-mixed-replace over HTTP. You can get it over at github.

The entire script after the jump.

Click to read more ...

Thursday
02Apr2009

I've updated frame animator

This is a followup to my previous article on my frame sprite animator for Core Animation. Read that article first, ff you haven't alreday.

I've updated my frame sprite animator. It's a little faster now, but more importantly, I've added a callback mechanism.

Callbacks

By default, a sprite is registered for HSAnimationModeLoop mode. But you can register an object to receive a callback from the animator when a sprite which has finished animating for the new animation mode HSAnimationModeOnce.

So for example, this is how to register a sprite to animate for the "KICK" frameset, set to animate only once, and then receive a callback.

[animator_ setCallback:self];
[animator_ registerSprite:sprite forFrameset:@"KICK" andAnimationMode:HSAnimationModeOnce];

And then implement the callback method.

- (void) hasFinishedAnimatingSprite:(CALayer*)sprite forFrameset:(NSString*)frameset {
  // Just re-register the sprite for the STAND frameset.
  [animator_ registerSprite:sprite forFrameset:@"STAND"];
}

It's as simple as that.

Source

I've updated the source over at GitHub. I've also updated the simple demo-application.