I decided to get more familiar with integration testing iOS applications. In the past I’ve found trying to do integration testing analogous with climbing the side of a cliff.

Given that I’m no Dread Pirate Roberts this has proven very challenging in the past. To challenge myself even further I decided to write an integration test around CoreLocation. In the simulator I can set a location for myself and to some degree I could test with this, but I wanted to be able to have different test scenarios given different locations.

One solution was to use something like FTLocationSimulator and do the following:
#ifdef FAKE_CORE_LOCATION
self.locationManager = [[FTLocationSimulator alloc] init];
#else
self.locationManager = [[CLLocationManager alloc] init];
#endif
But I’m not a big fan of adding conditional flags in my code. Also I don’t feel like I have a lot of control over what happens in my code. Instead I prefer doing something closer to dependency injection. Wherever I would normally do [[CLLocationManager alloc] init] I instead do [MyLocationManager sharedInstance]. MyLocationManager is a singleton which will delegate methods to it’s own locationManager. The basic setup looks something like:
#import "MyLocationManager.h"
#import <CoreLocation/CoreLocation.h>
@implementation MyLocationManager
@synthesize locationManager;
static MyLocationManager *sharedSingleton;
+ (id)sharedInstance {
static BOOL initialized = NO;
if(!initialized) {
initialized = YES;
sharedSingleton = [[MyLocationManager alloc] init];
}
return sharedSingleton;
}
- (id) init {
if (self = [super init]) {
locationManager = [[CLLocationManager alloc] init];
}
return self;
}
@end
And my fake location manager:
#import "CLLocationManagerFake.h"
#import <CoreLocation/CoreLocation.h>
@implementation CLLocationManagerFake
@synthesize desiredAccuracy;
@synthesize location;
-(id) init {
if (self = [super init]) {
self->location = [[CLLocation alloc] initWithLatitude:0.0 longitude:0.0];
}
return self;
}
- (void)startUpdatingLocation {
[self.delegate locationManager:self didUpdateToLocation:self->location fromLocation:self->location];
}
@end
And in my tests I can do the following:
CLLocationManagerFake *fake = [[CLLocationManagerFake alloc] init];
CLLocation *fakeLocation = [[CLLocation alloc] initWithLatitude:42.356426 longitude:-71.061993];
[fake setLocation:fakeLocation];
[[TTimeLocationManager sharedInstance] setLocationManager:fake];
Now I have complete control in my tests without polluting my actual code. If I want to use a different fake or have more control over specific scenarios I am able to do so with ease. I can also keep my test dependent code out of my final target.

“HE DIDN’T FALL? INCONCEIVABLE. “
In episode #3 of the Giant Robots Smashing into other Giant Robots podcast, Ben Orenstein is joined by Josh Clayton, the maintainer of FactoryGirl and a developer at thoughtbot.
Ben and Josh discuss FactoryGirl: using it, its development progress, and features. What it’s like to run an open source project, and how to contribute to open source effectively. Looking at your old code and being a better developer. Approaches to testing. And answer your questions about: FactoryGirl, How to write effective tests suites and whether integration tests are a scam, our process for upgrading between Rails versions, testing complex UI logic, and leaving code untested.
Call us toll-free at 1-877-9-ROBOTS x198 and leave a voicemail. That’s (877) 976-2687 x198, email your questions to info@thoughtbot.com or Tweet to us @thoughtbot.
Follow @thoughtbot, @joshuaclayton, and @r00k on twitter.
Want to speed up your test suite? Reduce the number of objects persisted to
the database. With Factory Girl, this is really easy; instead of using build
or create to instantiate your models with data, use build_stubbed!
build_stubbed is the younger, more hip sibling to build; it instantiates
and assigns attributes just like build, but that’s where the similarities
end. It makes objects look look like they’ve been persisted, creates
associations with the build_stubbed strategy (whereas build still uses
create), and stubs out a handful of methods that interact with the database
and raises if you call them. This leads to much faster tests and reduces your
test dependency on a database.
For example, let’s say we have an OrderProcessor that accepts instances of
Order and CreditCard. It hits the Braintree API and returns a boolean
value for if the charge actually happened.
class OrderProcessor
def initialize(order, credit_card)
@order = order
@credit_card = credit_card
end
def process
charge_successful? charge_customer
end
private
def charge_successful?(result)
# processes the result to determine if the result is valid,
# operating on the order and credit_card instance variables to
# add errors, send emails, or track Braintree's transaction id
end
def charge_customer
# runs Braintree::Customer.sale() with the appropriate options
end
end
None of this code hits the database. This allows us to write tests like:
describe OrderProcessor do
let(:transaction_id) { '1234' }
let(:order) { build_stubbed(:order) }
let(:credit_card) { build_stubbed(:credit_card) }
subject { OrderProcessor.new(order, credit_card) }
context 'when the Braintree result is valid' do
before do
MockBraintree.stub_successful_customer_sale(transaction_id: transaction_id)
end
it 'assigns the transaction id to the order' do
subject.process
order.transaction_id.should == transaction_id
end
it 'returns true for #process' do
subject.process.should be
end
it 'does not assign any errors to the credit card' do
subject.process
credit_card.errors.should be_empty
end
end
context 'when the Braintree result is invalid' do
before do
MockBraintree.stub_unsuccessful_customer_sale
end
it 'does not assign the transaction id to the order' do
subject.process
order.transaction_id.should be_nil
end
it 'returns false for #process' do
subject.process.should_not be
end
it 'assigns errors to the credit card' do
subject.process
credit_card.errors.should_not be_empty
end
end
end
Instead of creating twelve different records (at the minimum - if any of these factories have associations, you introduce more multipliers), we create none. This keeps the spec blazing fast.
Properly factored code should be small and concise. Code should typically depend
less on the state of the data in relation to the database and more on its
state in relation to other objects. In the above example, OrderProcessor
only handles dealing with Braintree and dealing with its errors; it does not
care about how this data is displayed to the user. That’s left for the
integration tests, which should be hitting the database.
Although it’s not useful in every situation (there are cases where you’ll want
data to exist, like when you’re testing uniqueness constraints or scopes),
build_stubbed should be your go-to FactoryGirl method over build or
create. Everyone running your test suite (yes, even yourself) will thank you.

Recently, we implemented a feature that required a before_filter in ApplicationController and whitelisting some other controllers using skip_before_filter.
We couldn’t actually test something like this directly because callbacks aren’t really methods. They’re entirely used for their side effects so we can only test what happens when we invoke one. Let’s check out an example:
require 'test_helper'
class ApplicationControllerTest < ActionController::TestCase
context 'ensure_manually_set_password' do
setup do
class ::TestingController < ApplicationController
def hello
render :nothing => true
end
end
ActionController::Routing::Routes.draw do |map|
map.hello '', :controller => 'testing', :action => 'hello'
end
end
teardown do
Object.send(:remove_const, :TestingController)
end
context 'when user is logged in' do
setup do
@controller = TestingController.new
end
context 'and user has not manually set their password' do
setup do
@user = Factory(:user, :manually_set_password => false)
login_as @user
get :hello
end
should 'redirect user to set their password' do
assert_redirected_to new_password_path(@user.password_token)
end
end
end
end
end
Note the use of the double-colon prepended to the TestingController, which ensures the class is top-level, not an inner class of ApplicationControllerTest. That way we can just do :controller => 'testing' and not have to write :controller =>
'application_controller_test/testing'. We also use the private method remove_const to remove the class after we’re done, so we don’t litter the namespace.