TechHui

Hawaiʻi's Technology Community

For whatever reason, testing did not seem to be a focal part of Apple's development tools until Xcode 5. Prior to then, tests were typically implemented using OCUnit, but it was difficult to integrate with the Cocoa framework. That changed in Xcode 5, where OCUnit was swapped out for XCTest and better testing support was added to Xcode. In addition to that change, the advent of CocoaPods let other developers create their own testing frameworks that can be installed into other user's Xcode workspace. This allows developers to create pods for different approaches to testing like Behavior Driven Development (BDD).

Those of us who work with Ruby on Rails regularly are aware of BDD thanks to RSpecKiwi is an iOS testing framework which acts very much like Rspec but for Objective C. Of course, the new hotness is now Swift and iOS8, so some of this may not apply. Kiwi is not compatible with Swift at the moment, although there are likely newer iOS frameworks out there that do support it. XCTest might also be worth checking out too, now that Apple has provided better integration for tests in Xcode 6.

There's a demo project up on Github. It was built on Xcode 6 and iOS 8 and there appear to be some bugs in it (as members of our local iOS group can attest to). Nonetheless, let me walk through some of the features in Kiwi and iOS testing.

Basic specs

Here's a simple Kiwi Spec


#import

#import "ViewController.h"

SPEC_BEGIN(ViewControllerSpec)

describe(@"ViewController", ^{

  let(controller, ^{return [[ViewController alloc] init];});

  beforeEach(^{

    [controller viewDidLoad];

  );

  it(@"initializes an empty list of incidents", ^{

    [[[controller incidents] should] beEmpty];

  });

});

SPEC_END

We start with a describe block, which tells us what we are testing. In it is a let block, which lets me declare a variable (controller in this case) that is created before each test. This makes sure we're always working with a fresh instance of a controller. We also have a beforeEach block where we do some pre-test setup. In this case, we're running the viewDidLoad function to trigger any view setup. Finally, we have an "it" block for our test. We are checking that the incidents array is empty (has 0 elements).

For those are unfamiliar with Rspec and specifications, this might look a little weird. One of the major differences between standard unit tests and specifications (specs) is that test names are more descriptive. When the test actually runs, the output would read as "ViewController initializes an empty list of incidents".

Mocks and Spies

The Hicrime app makes network requests, which makes testing difficult. Kiwi has built-in support for mocking and stubbing.


#import

#import "ViewController.h"

#import "AFHTTPRequestOperationManager.h"

SPEC_BEGIN(MocksControllerSpec)

describe(@"ViewController", ^{

  let(controller, ^{return [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"ViewController"];

  let(mockManager, ^{return [AFHTTPRequestOperationManager mock];});

  beforeEach(^{

    [AFHTTPRequestOperationManager stub:@selector(manager) andReturn:mockManager];

  });

  it(@"fetches using the data.honolulu.gov endpoint", ^{

    KWCaptureSpy *spy = [mockManager captureArgument:@selector(GET:parameters:success:failure:) atIndex:0];

    [controller loadView];

    [controller viewDidLoad];

    [[[spy argument] should] equal:@"http://data.honolulu.gov/resource/a96q-gyhq.json"];

  });

});

SPEC_END

In this spec, we're using AFNetworking's HTTPRequestOperationManager and mocking it out so that it doesn't actually run. We then create a spy to capture the URL parameter to AFNetworking's GET method. After calling viewDidLoad, we check that we received the correct URL endpoint for the crime data on the Honolulu open data site.

Continuous Integration

Facebook actually open sourced a build tool for Cocoa projects called xctool that's based off of Apple's xcodebuild. The main benefit is that xctool can be used for continuous integration. TravisCI, a hosted CI server that's free for open source projects, uses xctool by default to run your tests. All you need to do is provide the workspace file and the scheme for your project. A travis.yml for our system might look like:


language: objective-c
xcode_workspace: HICrime.xcworkspace
xcode_scheme: HICrime

For more info, check out their documentation on setting up an Objective C project. Also note that as of this writing, TravisCI does not have support for iOS 8. They should have support in the near future.

Testing with Kiwi worked pretty well in our last iOS 7 project. However, now that Swift is offically released, I'm on the lookout for a BDD framework that supports Apple's new language. If anyone out there has recommendations on a testing framework (or if you just stick to XCTest), let me know!

Views: 826

Comment

You need to be a member of TechHui to add comments!

Join TechHui

Sponsors

web design, web development, localization

© 2019   Created by Daniel Leuck.   Powered by

Badges  |  Report an Issue  |  Terms of Service