So last night I did some laundry, taught my oldest daughter how to write code, took both of my girls shoe shopping, washed the little one’s hair, raked the leaves cooked dinner, then finally got a start on trying RSpec against a Cocoa Touch controller class. Yep, I was kinda sorta busy. Had I a little more time I wouldn’t be stumped where I am now but since my schedule is as packed as a VW beetle carrying a family of 6 on a Ski vacation for 2 months there’s little wiggle room for discovery and surprises, so instead I ask you, my humble readers (all three of you) to figure out the hard stuff for me. I will gladly repay you by splattering your hard work across the internets next to a picture of my smiling eyebrows and deep claims referencing my name exclusively.
I’m working through a Bowled over by Ruby/Cocoa example written against Mac OSX Cocoa APIs and trying to adapt it to CocoaTouch. The first challenge comes from trying to use RubyCocoa to access a controller bound to certain CocoaTouch APIs like UIKit. It doesn’t work. So instead I was clever enough to side step the problem and generate my BowlingController as a vanilla NSObject using the “script/generate model” command from Dr. Nic’s RBiPhoneTest. I use rbiPhoneTest to setup the project test structure as well so now I have a rake file in my root that I use to build the necessary BowlingController.bundle for RSpec (or any Ruby code) to access. I will plan a write up on all of this after I get through the entire tutorial. Long story lengthened I have RSpec loading and running my BowlingController, I’ve made several iterations even into creating IBOutlet/IBAction bindings for Interface Builder. (I’m not sure if they work b/c I haven’t gotten that far yet.) I get stuck at the part where my controller is supposed to pass the pins value from the text field into the bowling model object. My Ruby bowling stub reports that roll has been invoked with no arguments even though I am most definitely passing a value into the method. I keep getting, “Spec::Mocks::MockExpectationError in ‘OSX::BowlingController should send the pin value to the bowling object’
Mock ‘Bowling’ expected :roll with (10) but received it with (no args)
./test/bowling_controller_spec.rb:38:” I’ve even went as far as passing a literal 10 into the call. At this point it looks like some sort of Ruby/Cocoa alignment issue or something.
bowling_controller_spec.rb
require File.dirname(__FILE__) + ‘/test_helper’
require “BowlingController.bundle”
OSX::ns_import :BowlingController
include OSX
describe BowlingController do
before(:each) do
@controller = BowlingController.new
@bowling = mock(‘Bowling’)
@text_field = mock(‘Pins’)
@text_field.stub!(:intValue).and_return(10)
@controller.pins = @text_field
end
it “should roll a ball” do
@controller.roll
end
it “should roll a ball and get the value from the pins outlet” do
@text_field.should_receive(:intValue).and_return(0)
@controller.roll
end
it “should be an OSX::NSObject” do
@controller.is_a?(OSX::NSObject).should == true
end
it “should have an outlet to a bowling object” do
@controller.bowling = @bowling
end
it “should send the pin value to the bowling object” do
@controller.bowling = @bowling
@bowling.should_receive(:roll).with(10)
@controller.roll
end
end
BowlingController.h
#import
@class UITextField;
@class Bowling;
@interface BowlingController : NSObject {
UITextField* pins;
Bowling* bowling;
}
@property (nonatomic, retain) UITextField* pins;
@property (nonatomic, retain) Bowling* bowling;
-(void) roll;
@end
BowlingController.m
#import “BowlingController.h”
#import “Bowling.h”
@implementation BowlingController
@synthesize pins;
@synthesize bowling;
-(void) roll{
[self.bowling roll:[self.pins intValue]];
}
@end
// This initialization function gets called when we import the Ruby module.
// It doesn’t need to do anything because the RubyCocoa bridge will do
// all the initialization work.
// The rbiphonetest test framework automatically generates bundles for
// each objective-c class containing the following line. These
// can be used by your tests.
void Init_BowlingController() { }
Bowling.h
#import
@interface Bowling : NSObject {
}
– (void) roll:(int) pins;
@end
Bowling.m
#import “Bowling.h”
@implementation Bowling
– (void) roll:(int) pins{
}
@end
// This initialization function gets called when we import the Ruby module.
// It doesn’t need to do anything because the RubyCocoa bridge will do
// all the initialization work.
// The rbiphonetest test framework automatically generates bundles for
// each objective-c class containing the following line. These
// can be used by your tests.
void Init_Bowling() { }
Note to self: I gotta find better analogies. These are really starting to suck.