Storyboards With Custom Container View Controllers

Storyboards With Custom Container View Controllers

iOS/OS X network testing with XCTest

I recently worked on a OS X app which had to keep in sync with a database running on a remote server, to interact with a hardware device via serial port and to allow the user to edit said database with information coming from the hardware device. Since reinventing the wheel is never a good idea, I decided to use various frameworks for those tasks: ORSSerialPort to handle the serial communication, AFNetworking for the networking, Apple’s own Core Data for the local database and XCTest together with OHHTTPStubs for the testing. The networking part was by far the easiest to develop but also the hardest to test, due to its asynchronicity.

This is basically how XCTest works: you create subclasses of XCTestCase, and then define instance methods with their name starting with “test”. Inside these methods you can check for whatever condition you need to test. Here’s a very simple example:

- (void)testReverseString{ 

    NSString *originalString = @"test";
    NSString *reversedString = [self.controllerToTest reverseString:originalString];
    NSString *expectedReversedString = @"tset";

    XCTAssertEqualObjects(expectedReversedString, reversedString);
}

XCTAssert allows to easily compare variables and to let tests fail/succeed based on the result, but it is not enough when it comes to testing the networking code. For example, I needed to test a GET request that fetched the user database from the remote server and tried to do so this way:

- (void)testSuccessfulUserFetch
{

    // Perform fetch
    [self.networkManager fetchUsers];

    // Test if the number of users created in the local database is equal to the one in the remote database
    NSArray *localUserDatabase = [User usersInManagedObjectContext:self.moc];
    XCTAssertEqual([localUserDatabase count], 10);

}

The test failed even if the GET was performed with success, because the local database was tested right after the network request was started and not after its completion.

Luckily Xcode 6 introduced a new feature in XCTest that allows to test asynchronous code as well: XCTestExpectation. It’s as easy as declaring an expectation and setting a timeout for that expectation. The only other thing that’s needed is of course to check for whatever condition has to be met and to fulfill the expectation if that happens.

The obvious place to check and fulfill my network expectations was inside the success/failure blocks that my network manager used, but since that code was written way before I decided to write tests for it, there was no easy way to do so without refactoring. At first I felt like it was not a very good idea to refactor the network manager just to be able to test it, but I’m glad I did: while the existing code was working fine, refactoring it and being able to test it afterwards helped a lot while further developing it.

This is how I changed on of my NetworkManger.m methods to use optional success/failure blocks:

typedef void(^SuccessBlock)(AFHTTPRequestOperation *operation, id responseObject);
typedef void(^FailureBlock)(AFHTTPRequestOperation *operation, NSError *error);

// Perform network request for user database
- (void)fetchUsersWithSuccess:(SuccessBlock)optionalSuccessBlock
         withFailure:(FailureBlock)optionalFailureBlock
{
    // Create success block
    SuccessBlock successBlock = ^(AFHTTPRequestOperation *operation, id responseObject){   

        // Load users into the database
        NSArray *usersArray = (NSArray *)responseObject;
        [User loadUsersFromArray:usersArray inManagedObjectContext:self.managedObjectContext];

        // Optional success block, if given
        if (optionalSuccessBlock) optionalSuccessBlock(operation, responseObject);
    };  

    // Create failure block
    FailureBlock failureBlock = ^(AFHTTPRequestOperation *operation, NSError *error){

        // Optional failure block, if given
        if (optionalFailureBlock) optionalFailureBlock(operation, error);
    };  

    // Perform request to server
    [self.manager GET:self.userSyncURL parameters:nil success:successBlock failure:failureBlock];
}

And here’s what the test method looks like:

- (void)testSuccessfulUserFetch{
    // Create expectation
    XCTestExpectation *countExpectation = [self expectationWithDescription:@"User count expectation"];

    // Create custom success block
    SuccessBlock successBlock = ^(AFHTTPRequestOperation *operation, id responseObject){
        // Check and fulfill expectation
        [self checkUsersAndFullfillCountExpectation:countExpectation];
    };

  // Wait for expectations to be fulfilled. If timeout is met, test fails.
  [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {
    if (error) {
      NSLog(@"Timeout Error: %@", error);
    }
  }];
}

// Check expectations for successful user fetch
- (void)checkUsersAndFullfillExpectation:(XCTestExpectation *)countExpectation{

  // Check the users count in the database
  NSArray *users = [User usersInManagedObjectContext:self.moc];
  if ([users count] == 10){
    [countExpectation fulfill];
  }
}

Learn Apple’s Swift Language: free online resources

During a meeting last week, I was discussing with a colleague about Swift courses, in his view it’s too early to attend a Swift course because nobody has mastered it completely yet. I think it’s better, in the beginning, to build your knowledge with online resources. But besides the iBook and the official documentation released by Apple*, what are some good resources to start learning Swift?  Continue reading “Learn Apple’s Swift Language: free online resources”

Pimp my TextMate2 — Ruby edition

Here at Mikamai It’s no secret I’m a happy TextMate user and early TM2 adopter. I’m always there if either an editor war is catching fire or if someone needs help setting up his editor.

Above all I still find that TextMate is the best choice for a Ruby developer, even if SublimeText, emacs and vim seem more fashionable these days. Even if I’m saving the full list of reasons for another post I’ll tell just this one: TextMate relies on Ruby for a big part of its implementation that has always been opensource*.

Of course I’m talking about bundles, if you’re not convinced look at the code used to align assignments (⌥⌘]) from the source bundle (which is responsible for actions common to any programming language).

Just to be clear I would still use SublimeText if I were to program from Linux or (ugh!) Windows.

That said I want to gather here some of the stuff that makes using TextMate2 for Ruby and Rails development so awesome.

* Of course I know about redcar (which seems quite dead, but I didn’t tried it recently) and other TM clones err enhancements like Chocolat

ALERT: shameless self promotion follows

The Bundles and Settings parade

1. Effortless opening of Bundled Gems ⌥⌘O

This I do all the time, opening the source of bundled gems. Please behold and don’t be horrified. Especially in Ruby-land the source of gems is the best source of documentation, and as explained by Glenn Vanderburg) there’s probably a good reason for that. Also the README and specs are included most of the time and reading other’s code is a healthy activity.

Needless to say that the best place to read source code is your editor.

⌥⌘O will present the complete list of gems from your Gemfile.lock, start typing the first letters of a gem and use arrow if you don’t want to touch the mouse (or trackpad).

opening gems from the current bundle

Source: https://github.com/elia/bundler.tmbundle

2. Beautiful Markdown rendering

No README.md reading activity would be on par with a the GFM rendered version without code blocks highlighting.

This bundle almost looks like GFM while typing, press ⌃⌥⌘P (the standard TM key equivalent for preview) to get it rendered to the HTML window.

Redcarpet Markdown Bundle in action

Bonus Install the Scott Web Theme from Preferences → Bundles for a nice looking preview

Source: https://github.com/streeter/markdown-redcarpet.tmbundle

3. Restart Pow! in a single stroke ⌃⌥⌘R

Restarts the current app detecting a tmp/ directory in current project or in a parent dir.

Falls back to /tmp

Source: https://github.com/elia/pow-server.tmbundle

4. Open the terminal in your current project folder

Works with both Terminal and iTerm, just press ⌃⌥⌘T from a project.

Source: https://github.com/elia/avian-missing.tmbundle

5. Trailing whitespace fix, cross-tab completion and more…

Command Description
⌃⎋ Cross tab completion
⌃⌥⌘T Open Project directory in Terminal
⌃⌥⌘L Keep current file as reference

Source: https://github.com/elia/avian-missing.tmbundle

Installing the whole thing

Download the latest version of TextMate2 here: https://api.textmate.org/downloads/release

mkdir -p ~/Library/Application Support/Avian/Bundles
cd ~/Library/Application Support/Avian/Bundles

git clone https://github.com/elia/avian-missing.tmbundle
git clone https://github.com/elia/bundler.tmbundle
git clone https://github.com/streeter/markdown-redcarpet.tmbundle

# Activate the system ruby (if you're using a Ruby version manager):
type rvm &> /dev/null && rvm use system # for RVM
export RBENV_VERSION="system"           # for rbenv

# Install the required gems
sudo gem install redcarpet -v 2.3.0
sudo gem install pygments.rb

# Trailing whitespace
defaults write com.macromates.TextMate.preview environmentVariables -array-add 
    '{ "enabled" = YES; "name" = "TM_STRIP_WHITESPACE_ON_SAVE"; "value" = "true"; }' # enable trailing whitespace removal and EOF fix

echo <<-INI >> ~/.tm_properties
[ "*.y{,a}ml" ]
# Disable trailing whitespace fix for YAML 
# files that can be broken by this feat.
TM_STRIP_WHITESPACE_ON_SAVE = false
INI

The following will set the tabs/file-browser/html-windows to my current taste, I don’t pretend it matches everyone prefs but can still be useful for cherry-picking.

# File browser fixes and general UI fixes
defaults write com.macromates.TextMate.preview fileBrowserStyle SourceList       # lighblue file browser background
defaults write com.macromates.TextMate.preview fileBrowserPlacement left         # keep it on the left
defaults write com.macromates.TextMate.preview tabsAboveDocument -bool YES       # no tabs above the file browser
defaults write com.macromates.TextMate.preview allowExpandingLinks -bool YES     # make symlinks expandable
defaults write com.macromates.TextMate.preview htmlOutputPlacement right         # place the html output to the right
defaults write com.macromates.TextMate.preview disableTabBarCollapsing -bool YES # keep the tab-bar alway visible
defaults write com.macromates.TextMate.preview scrollPastEnd -bool YES           # give me some air after the file ends