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;

…should be coded like this:

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

…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 suport from 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.

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 are 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 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)
  # def method_missing(m, *args)  
  #   puts "Forwarding message"
  #   @delegate.send(m, args)
  # end
  def initialize(theMock)
    @delegate = theMock

describe BowlingController do
  before(:each) do
    @controller = BowlingController.new
    @bowling = mock('BowlingProtocol')
    @controller.bowling = ObjCMock.new(@bowling)
    @text_field = mock('Pins')
    @controller.pins = @text_field

  it "should roll a ball" do

  it "should roll a ball and get the value from the pins outlet" do

  it "should be an OSX::NSObject" do
    @controller.is_a?(OSX::NSObject).should == true

  it "should have an outlet to a bowling object" do
    @controller.bowling = @bowling

  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

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

//  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];


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