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…

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.

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.