Unit Testing Objective-C Using Kiwi

January 17, 2013

I have released AFImageDownloader to the open source community. It, asynchronously, downloads JPEGs from the Internet and decompresses them on a background queue.

[AFImageDownloader imageDownloaderWithURLString:@"http://static.ashfurrow.com./github/worked.jpg" autoStart:YES completion:^(UIImage *decompressedImage) {
    self.imageView.image = decompressedImage;

Network calls obviously take a long time and must not be performed on the main thread. JPEG decompression can actually take a long time if it’s performed on a large image or on small images very frequently. It can be a common cause of performance problems.

What I’m really excited about is that it is the first Objective-C project I’ve developed using strict TDD/BDD using Kiwi. Until I was completely finished writing the code, I had only tested it using unit tests — never letting it touch the Internet at all. The first time I ran it, it worked perfectly.

(While I think that blindly adhering to TDD may not be a wise choice for iOS development, I wanted to see if I were up to the challenge.)

Kiwi encourages Behaviour-Driven Development. While the setup is a little arduous, it was a joy to work with.

describe(@"Image downloader", ^{
    NSString *urlString = @"http://example.com/image.jpeg";
    __block AFImageDownloader *imageDownloader;

    context(@"has been newly created", ^{
            imageDownloader = [[AFImageDownloader alloc] initWithURLString:urlString autoStart:NO completion:nil];

        it (@"should create a new URL connection when started", ^{
            [[imageDownloader should] 
            [[imageDownloader should] 
            [imageDownloader start];

        it (@"should return a URL request with the proper URL string", ^{
            NSURLRequest *request = [imageDownloader urlRequestForURLString];

            [[request.URL.absoluteString should] equal:urlString];

        it (@"should start the new URL connection", ^{

            [imageDownloader start];

        it (@"should be set it state to started when started", ^{
            NSURLConnection *urlConnectionMock = [NSURLConnection mock];
            [[urlConnectionMock should] receive:@selector(start)];

            [imageDownloader stub:@selector(urlConnectionForURLRequest:)

            [[imageDownloader should]
                receive:@selector(setState:) withArguments:theValue(AFImageDownloaderStateStarted), nil];
            [imageDownloader start];

I’m looking for any feedback you have about the code, the structure of the project, or the testing I’ve performed.

Please submit typo corrections on GitHub