OCMock Woes


So I’m building and running tests and banging my head against oncoming traffic while trying to get the OCMock framework to do something… I dunno… mocky? I’m running Xcode 4.2 build (4D199) on Lion. Dragging and dropping the freshly downloaded “.framework” bundle doesn’t want to link. Hi, I’m Cliff and you’re here because you have linker errors in your XC4 project while trying to get objects to pretend to be other objects. I’m here to try to help you work through some of the issues.

So I try building the static lib and forcing it. The first roadblock I hit was with the ${BUILD_STYLE} environment no longer being set. ${BUILD_STYLE} is changed to ${CONFIGURATION} in Xcode 4. The second bump I hit was with categories not loading from the static lib I generated. Setting “-ObjC” under “Other Linker Flags” solved this. Next I get OCMock to load but auto complete doesn’t work with the category methods added to “id”. (Eg. stub, expect, verify, etc.) I accidentally set my “Header Search Path” incorrectly. You have to set it to point to the folder that contains the OCMock folder with the header files in it, then you can successfully import in your test cases. Finally auto-complete works and things load but setting simple expectations on a mocked string appears to be broken. I’m now wondering if I should download source from the git repo instead of building the source included in the dmg. It’s late and I’m incredibly frustrated with not being able to write a single test all day…

XCode 3.2.4 Bug!


Just a quick note to those of you working with XCode 3.2.4 and trying to get any sort of unit testing working. There is a known bug/issue in XCode that causes unit test builds to crash. As it is written here (and here), “some part of the reporting code not respecting timezone issues. The output is tagged as ending before it began, so gets very confused and chokes.” The solution is to edit the Run Script step of the unit test target and make it look like this:

"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests" 1> /tmp/RunUnitTests.out 

Works for me!

Objective-C Gotchas


You’re working in Objective-C land trying to get a product out the door and into the Apple iTunes Store, right? (Don’t argue with me I’m just setting the stage.) You’re feeling the second cup of coffee seep into your bloodstream which creates a certain euphoric sensation as the last 3 times you mashed Cmd+B turned up no errors. Yes, that’s what’s happening in your copy of XCode right now. You then Cmd+Tilde to toggle the other XCode window active (Cmd+Tilde is a nifty Apple shortcut for switching active windows in the current app) and Cmd+B once again when a red flag on the play pops up in some code that had been just fine moments ago? What happened? Hi, I’m Cliff. You’re here because XCode got’cha and you’re not quite sure how/why/where. I’m here because I wanna list as many of these got’chas before I forget them.

Property accessor notation in Earlier SDKs
Here’s one weird gotcha that I just hit again for the first time. If you have a variable typed as a protocol and that protocol has a setter, which takes another protocol type defined then you may get an error when using dot notation in SDKs earlier than 3.0. That is a definition like this:

@protocol MyCoolAbstractType <NSObject>
-(void) setNetworkDataProvider:(id<MyNetworkDataProvider>)aNetworkDataProvider;
@end

…should be coded like this:

@protocol MyCoolAbstractType <NSObject>
@property (nonatomic, retain) id<MyNetworkDataProvider> networkDataProvider;
@end

…before you can do this:

id<MyCoolAbstractType> myObj = //create object from factory
myObj.networkDataProvider = [[MyConcreteNetworkDataProvider alloc] init];

Evidently the “Discover setter is a property” feature is something new Santa delivered with 3.0 and never told me about. Here I thought I had that toy from 2 years ago!

Unit Tests Can’t Be Signed
I added a unit test dependency to my “Application” target the other week in order to streamline my dev cycles. The idea was to ensure any changes I made to satisfy the integrated application bundle did not impact behaviors outlined in my test cases. (I use mini applications to perform my integration testing.) The problem here is that, even though this works well for simulator builds, an on-device build will fail as XCode attempts to sign your unit test target output. I haven’t discovered a work-around for this one yet so I’m gonna just punt and remove the test dependency from any targets meant to run on device.

I’ll trow up more as I find them…

How not to link a framework in iPhone dev


With much help from Erik, the owner of OCMock, I discovered how much of a loon I can be. Let me set the stage with a story, like I typically do on this site. You’re writing unit tests for a spankin’ new iPhone project that’s gonna shake the world if it ever releases. You’ve got backing support of everybody from MGM Studios to Barack Obama helping you to make your release date. You are an advocate of all things Agile, TDD, and behavior driven. You absolutely cannot fail! You now need to do something clever in your unit tests. Something Apple doesn’t provide facilities for. You find a framework that does it. Maybe you’re bringing in OCMock or maybe you’re just trying to link Hamcrest. Hi, I’m Cliff. You’re here because your framework won’t load in your unit tests. I’m here to tell you how not to link against it.

lassard

Many, many years ago (like 1), I tried to link against OCMock. The only way to make it work was to drop it into the magic place called “/Library/Frameworks/”. It worked. It worked well. It worked so well that I decided to become the OCMock super hero. I wrote a blog about it. (Like to hear it? Here it go!) I wrote an OCMock setup thing with Automator/AppleScript for other developers that weren’t as John Blazed as I was so that they too could enjoy the beauty that was OCMock. (Just had a flashback to the little stored procedure runner tool I wrote when I was being the VB6-toRPGIV super hero many more years ago.) Here’s where a super hero becomes a super zero.

I neglected the principles of software development. Anything that goes in a System folder is visible to everything. Putting files, tools, trinkets there is always error prone, remedies for disaster. Why? Because it’s fire and forget… A one time setup that you never need to worry about. The “forget” part of the “fire and forget” is what bites. The one time step that you always need to think about when troubleshooting but never do. Like I said, a year passes and I haven’t done much with OCMock except for occasions. Now I wanna upgrade to the latest version. I’ve since learned a better way to link projects to frameworks but my machine still “remembers” the old way. My new process, from memory, goes something like:

  • Find a framework
  • Drag/drop it into your project
  • Do something in the build configs, like setting a framework search path
  • I think that’s it, right? Yeah. Compile and run and I see the green button. I’m good!

Everything works as expected. I’m pretty sure I’m picking up the right version because I just double clicked the little framework icon and triple checked the path pointing to the newly downloaded folder. I could go the extra mile and look for the notes I wrote last year and make sure there’s no other gotcha’s but things are working. Why bother?

There’s two critical problems here. the first is that I never removed the frameworks from the magic “fire and forget” place. Just don’t put things here and you’ll never have to remember to delete them when you upgrade or when they break other things. The second problem is that I didn’t remember my new method for linking because my machine still remembered the old way making me feel like I was all good. The better way to link frameworks in iPhone dev is to put a “copy files” build phase into your target, set the destination path to “products directory” and drag/drop your frameworks into this phase. One caution is that while you can run on the Mac using the Simulator you still can’t load frameworks on the device. So I conclude this long winded article that could have been summarized in 2-3 sentences by saying, if you wanna suck at programming overload your system folders with development frameworks and libraries. Not only will you immediately solve the problem at hand and meet your immediate deadline but you’ll break the next twelve identical problems in the future and miss all of those deadlines. Good luck making up weeks of productivity lost chasing a problem that only exists on your machine. Good luck making up several more weeks of lost productivity while you reinstall your OS and lose several other important files/temporary projects trying to fix the problem that only happens on your machine.

Mock It To Me!


I’m playing with OCMock on a random iPhone project and having nothing but pain. Naturally my only outlet is to you, dear reader. Thanx for stopping by and thank you all for the comments you’ve been leaving. Not everyone realizes how important it is not only to comment with well formed answers but to reply with well thought out questions and problems. We all suck our knowledge from the same cloud of computers nowadays. I don’t know about you but I constantly find myself trapped behind a convoluted compiler or runtime error and an unanswered question on some forum. No matter how good Stackoverflow is getting these days it still does not have AI and cannot answer all of your questions in twenty minutes or less. That leaves many adventures and problematic programming paths without a “happy ever after”. Hi, I’m Cliff. My job is to continually post cryptic compiler messages and explanations on this site for all to follow. One day my Ode to an EmptyStackException will be the saving grace of a project on the brink of a deadline. (I’ll gladly share my PayPal to those interested in tipping should any of my topics be informative enough to land such a multi-million dollar deal.) I digress.

Today, as I was saying earlier, I wrestle OCMock for iPhone development. When I setup an iPhone project I drag/drop the OCMock.Framework folder in, attach it to my UnitTests target, and double check the framework search paths build property for my test target. I then use a slightly modified version of the OCMockObjectTests to validate all of the features are available. On my latest project I got anal. There was a particular feature (ordered method invocations) that wasn’t in the release I downloaded last year. I updated my version of OCMock then instead of modifying its test suite I copied it into my project. Certain things wouldn’t compile for one reason or another so I hacked around a bit. I got down to a snippet that was attempting to return a “BOOL” from a mock and began seeing these errors:


expected specifier-qualifier-list before 'typeof'

I remember these errors from a while ago when I ran across an article describing a similar solution. I hacked the code around a bit going as far as to download OCMock's source and run the tests from within. The funny thing is that these tests pass without issue, possibly because they're running in OS X world. When run in iPhone world things seem to be slightly different. Here's what I see in particular.

This works:

BOOL variable;
[NSValue value:&variable withObjCType:@encode(BOOL)]

This doesn't work:

BOOL variable;
[NSValue value:&variable withObjCType:@encode(typeof(variable))]

There are a few other subtle issues that I can't get into because I hacked around so much I lost my place. I'm now facing a "Bus error" when I run through the remaining tests. I you know what I don't, then type one of those comment things. You'll not only improve my life, but you'll enrich the lives of hundreds of Googling souls facing similar trouble.

CoverStory on IPhone projects


I really, really, really don’t care about test coverage when I develop because it’s one of those things you get for free when you follow the right practices. I always thought projects like Clover and Cobertura were a waste of time. However I recently started dreaming up an interesting use case for these kind of tools. Help me, if you will, get CoverStory (a test coverage tool for ObjC) up and running so I can prove myself wrong. I’ve followed the [sparse] documentation and steps on the CoverStory home site. There’s a section on including an alternate, fat libgcov.a file that confused me. Not knowing what path to what file or where to set the path I stumbled on a way of satisfying the “no such file for -lgcov” error by dragging/dropping the fat libgcov.a file into my project. Now when I build I get the .gcno files but no .gcna files and Coverstory won’t report coverage. CoverStorySettings

RSpec 4 iPhone BDD?


Is anybody doing this yet? I made an effort to use RSpec for iPhone development almost a year ago but got stumped on Ruby mock objects that didn’t seem to to play nice with CocoaTouch objects. I got a lot closer than my blog post would lead you to believe but stopped due to deadlines, and my lack of experience with both Ruby and ObjC. Tonight I dug up the old project and tried to remember where I left off…

…Aahh it’s al coming back to me now! I had wrapped the MockObject support in Ruby to ensure it received parameters from CocoaTouch. For some silly reason parameters passed directly from CocoaTouch objects are dropped/ignored by whatever mock framework Ruby is using with RSpec. Forgive me for not knowing more about the internals but I don’t do Ruby and this was from last November. Here’s an example of the RSpec I modified to allow parameters to pass cleanly. It also has the buddings of a dynamic message dispatch thingy I couldn’t get working because it makes no sense to hard code every anticipated method invocation. If one of you Ruby guys could jump in and patch this up or if somebody could point me to an already viable alternative that’d be so swell…


require File.dirname(__FILE__) + '/test_helper'

require "BowlingController.bundle"
OSX::ns_import :BowlingController
OSX::ns_import :BowlingProtocol
require 'delegate'

include OSX

class ObjCMock
  attr_accessor :delegate
  def roll(num)
    @delegate.roll(num)
  end
  
  # def method_missing(m, *args)  
  #   puts "Forwarding message"
  #   @delegate.send(m, args)
  # end
    
  def initialize(theMock)
    @delegate = theMock
  end
end

describe BowlingController do
  before(:each) do
    @controller = BowlingController.new
    @bowling = mock('BowlingProtocol')
    @bowling.stub!(:roll)
    @controller.bowling = ObjCMock.new(@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
    #This line wraps the mock with the class defined above
    @controller.bowling = ObjCMock.new(@bowling)
    #The following line will cause failure calling directly into the mock
#    @controller.bowling = @bowling
    @bowling.should_receive(:roll).with(10)

    @controller.roll
  end
  
  it "should have an outlet to the score" do
    @score = mock('Score')
    @controller.score = @score
  end

end
//
//  BowlingController.h
//  BowlingController
//
//  Created by FIXME on 2008-11-10.
//  Copyright 2008 FIXME. All rights reserved.
//

#import "BowlingController.h"
#import "BowlingProtocol.h"

@implementation BowlingController
@synthesize pins;
@synthesize bowling;
@synthesize score;

-(void) roll{
	int val = (int) [self.pins intValue];
	printf("Value is: %i", val);
	[self.bowling roll:val];
}

@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() { }

iPhony Frameworks


So I’m writin’ all kinds of Objective-C code, right? And I’m finally in my element because I got Google Tools For Mac doin’ the SenTest thing, right? I even figured out how to include modules using project relative paths. That’s when my trouble started. Y’see, I thought frameworks were no different than modules. Of course they’re different or else they wouldn’t be called frameworks! Still, I blurred the line between the two. So then I’m writing all these gnarly tests using OCMock. Remember OCMock? I complained on the forums about adding it to an iPhone project. then I finally found a hack to get it to run in my iPhone tests. Then the whole module thing started to make me feel warm and fuzzy inside so I thought I had a better approach. At any rate, I tried the same approach with Hamcrest, a tool advertised on the OCMock home page. I couldn’t get it to work. Finally, it dawned on me! You can’t add frameworks to iPhone projects! [Honestly it didn’t dawn on me, I had to be told then re-told by someone who knows waaay more about iPhone stuff than me.]

The point is that Frameworks in XCode iPhone projects don’t work like modules. With a module, you can just drag/drop the module file into your project, set its dependencies in your target, build and then you’re off and running. Frameworks are different. Frameworks have to exist (to the best of my knowledge and until someone who knows stuff tells me some new stuff) under /Library/Frameworks in order for SenTest test cases to use them. Frameworks can not be used at all during run time in an iPhone project. I don’t even think they’ll run in the Simulator which means no debugging unit test code, which means you better write some very fine grained unit tests which turns out to be necessary anyhow. That’s the point. You can’t run Framework code in an iPhone project but you can run it in a GTMSenTestCase as part of the build (not build/go process). If anybody knows better speak up now or I’ll forever hold out the peace sign.

Dynamic Dispatch Discrepancy


*Update*
By the way I unsuccessfully tried overriding the methods() method and almost went as far as overriding send on my mock wrapping ObjCMock class. My experience in MOP tells me that overriding send is likely rooted in trouble so I decided against it.

Yesterday’s Ruby drama ended with my finding a hack around the dropped parameters. If I was more familiar with Ruby, had more time to kill, or if it were Groovy instead then my solution would be much cleaner.

The problem:
Ruby Mocks under RSpec (have no idea if the problem persists in other Ruby scripting environments) do not receive parameters correctly from native Cocoa objects.

The hack:
Use a home-grown mock to intercept the parameter and pass along to the Ruby mock.

The code: (bowling_controller_spec.rb)

require File.dirname(__FILE__) + ‘/test_helper’

require “BowlingController.bundle”
OSX::ns_import :BowlingController
OSX::ns_import :BowlingProtocol
require ‘delegate’

include OSX

class ObjCMock
attr_accessor :delegate
def roll(num)
@delegate.roll(num)
end

# def method_missing(m, *args)
# puts “Forwarding message”
# @delegate.send(m, args)
# end

def initialize(theMock)
@delegate = theMock
end
end

describe BowlingController do
before(:each) do
@controller = BowlingController.new
@bowling = mock(‘BowlingProtocol’)
@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 = ObjCMock.new(@bowling)
# @controller.bowling = @bowling
@bowling.should_receive(:roll).with(NSNumber.numberWithInt(10))

@controller.roll
end
end

I left in the commented out method_missing magic that doesn’t work the way I’d expect it. Ideally I’d like to tuck this wrapping mock to the side without needing to define the specific signature I’m mocking. Ideally method_missing would give me the ability to answer any message. Alas, I get “does not reckognize selector” errors from NSProxy when I enable it. I have a feeling that NSProxy probably looks through the defined methods on it’s delegate and throws this error without 1st trying to invoke the method… effectively killing any dynamic magic ability from objects passed into Cocoa land. I also have a feeling that there are a few other holes in the proxy approach with Ruby/Cocoa. If anybody happens to know the details feel free to chime in.

RSpec for iPhone development


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.