Using OCMock with Mac OS X Lion, Xcode 4, to Mock and Unit Test Cocoa Desktop Apps

If you’re trying to learn how to use OCMock, you’ll encounter a number of articles dedicated to using it with iOS. You won’t find very many related to writing tests, mocks, and stubs for your Cocoa desktop applications for OS X Lion. If you’re writing your apps to exclusively target OS X Lion (10.7), then this article will be of use to you. I’m not sure if this technique will work for Snow Leopard apps or not. But, since OS X Lion 10.7 is a 64 bit OS the distributable library in the downloadable package (1.77) will not work. Hence, the reason for writing this article.

Here are the steps that you need to follow, you will create a brand new demo application that will demo using OCMock. You should be able to apply part of these instructions to your own project.

I should preface these instructions by stating that I am not an Xcode or Objective C expert. Also, I’m using Xcode version 4.1 despite version 4.2 being available. I just haven’t upgraded yet.

Building 64-bit OCMock Library

This is the first necessary task. As stated earlier, the libOCMock.a file found in the downloadable package is 32 bit only.

  1. Download the latest OCMock package. At the time of this writing, it’s version 1.77. It’s conceivable that later versions will include the 64 bit version and you’ll be able to skip these steps entirely.
  2. Mount the package and extract the Source and Release directories.
  3. Navigate to Source/ocmock-1.77 and open up OCMock.xcodeproj
  4. When Xcode opens up, click the root node “5 targets, multiple platforms” of the project navigator. The project’s build settings will show up. Observe that there are 5 targets: OCMock, OCMockTests, OCMockPhoneSim, OCMockPhoneDevice, OCMockLib
  5. Notice how there are 4 projects schemes: OCMockPhoneSim, OCMockPhoneDevice, OCMock, and OCMockLib
  6. Notice how there are four products: OCMock.framework, OCMockTests.octest, libOCMock.a, and libOCMock.a
  7. Recall, that we are most interested in a 64 bit libOCMock.a
  8. Delete the target OCMockPhoneSim. Select it. Right click and hit ‘Delete’ You should notice that one of the libOCMock.a products disappears, leaving us with one left.
  9. You should still be in the OCMockPhoneSim target with “My Mac 64-bit” Select the target OCMockPhoneDevice. Change the Base SDK to Mac OS X 10.7 on every dropdown that you can.
  10. Change Architecture to 64-bit on every drop down that you can.
  11. Remove i386 from Valid Architecture.
  12. Change scheme to “OCMockLib – My Mac 64-bit”
  13. Click ‘OCMockLib’ target. Click ‘Build Phases” and then expand the ‘Run Script’, remove the following text:
    # combine lib files for device and simulator platforms into one
    
    lipo -create "${BUILD_DIR}/${BUILD_STYLE}-iphoneos/libOCMock.a" "${BUILD_DIR}/${BUILD_STYLE}-iphonesimulator/libOCMock.a" -output "${TARGET_BUILD_DIR}/Library/libOCMock.a"
    
     
    
    # copy the headers (we could have used a copy files build phase, too)
    
    cp -R "${BUILD_DIR}/${BUILD_STYLE}-iphoneos/Headers" "${TARGET_BUILD_DIR}/Library"
    
  14. Click ‘Build’ from the ‘Product’ menu. 64 bit libOCMock.a should be built now. Right click libOCMock.a in the project navigator under the ‘Products’ group. Click ‘Show in Finder’. Copy libOCMock.a and the directory OCMock founder in the Headers directory that is located in the same directory as libOCMock.a. Copy these two items to a location that you can find them later.

Adding OCMock to the Demo Project

Now we’ll add the library and header to a demo project.

  1. Open Xcode. Click File…New Project. Select Cocoa Application.
  2. Name it whatever you want. Make sure that you click “Include Unit Tests”
  3. Verify that the default test is working… click Product…Test You should get a test error in the testing file. If so, works as expected.
  4. Navigate to your project directory. Create a directory in it called ‘TestLibraries’
  5. Copy libOCMock.a and the folder ‘OCMock’ containing the header files into the ‘TestLibraries’ directory.
  6. You’ll have a group (folder) that is named like so: (YOUR_PROJECT_NAME)Tests. We’ll refer to this as the testing group. Right click it and click ‘Add Files to..’
  7. Select the folder in your project directory that you created: ‘TestLibraries’ Make sure that “Copy items into designations group’s folder” is NOT checked since these files already exist at the project root. Select ‘Create groups for any added folders’. Uncheck your project target and make sure that your testing target is checked.
  8. Go to the Test target build settings. Make sure that: “Library Search Paths” has “TestLibraries” in it. If not, you’ll need to add the following string WITH THE QUOTES: “${SRCROOT}/TestLibraries”
  9. In the Test target build settings, make sure that “Header Search Paths” has “TestLibraries” with recursive selected. If not, add the following string WITH THE QUOTES:  ”${SRCROOT}/TestLibraries” Select the ‘recursive’ option.
  10. In the Test target build settings, locate ‘Other Linker Flags’, add: -ObjC -all_load
  11. In your implementation test file, locate the textExample method. Put this snippet in its place:
    #include <OCMock/OCMock.h> //put this at the top
    id mockString = [OCMockObject mockForClass:[NSString class]];
    
    [[[mockString stub] andReturn:@"MOCKS UP IN"] lowercaseString];
    
    STAssertEqualObjects([mockString lowercaseString], @"MOCKS UP IN", nil);
    
  12. Click “Product” menu and “Build For Testing”
  13. Then click “Product” and “Test” All should pass.

If you get the following error: ‘unrecognized selector sent to instance’ then you didn’t at the ‘Other Linker Flags’

Hope this helps. References:

Do you use Git? If so, checkout Gitpilot to make using Git easy.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Synchronous File Copy in Node.js

Sometimes, asynchronous operations can be a burden. Especially when you’re writing small console utilities like to batch process files.

There are many asynchronous ways to copy a file. Here is a synchronous version (CoffeeScript):

copyFileSync = (srcFile, destFile) ->
  BUF_LENGTH = 64*1024
  buff = new Buffer(BUF_LENGTH)
  fdr = fs.openSync(srcFile, 'r')
  fdw = fs.openSync(destFile, 'w')
  bytesRead = 1
  pos = 0
  while bytesRead > 0
    bytesRead = fs.readSync(fdr, buff, 0, BUF_LENGTH, pos)
    fs.writeSync(fdw,buff,0,bytesRead)
    pos += bytesRead
  fs.closeSync(fdr)
  fs.closeSync(fdw)

You can view the converted version in JavaScript.

Do you use Git? If so, checkout Gitpilot to make using Git thoughtless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Buzz: A Node.js Command Line Program to Keep Your App Running Indefinitely; Like the Program Forever

Buzz is a command line program that can kill your app routinely and restart it.
It’ll will also restart your app if it dies. It’s a lot like the other Node.js
program Forever.

It’s much simpler than Forever. Approximately 50 lines of CoffeeScript code.
It displays your apps output to STDOUT and also displays any of your apps
STDERR output in red.

Usage

Install it via npm:

npm install buzz

Then run:

buzz 240 your_cool_app param1 param2

The first parameter to buzz is the time in seconds that it’ll be killed and
restarted. So, `your_cool_app` would be killed and restarted after four minutes.

If you don’t want buzz to kill your app, but you want it to bring it back to
life if it dies, run:

buzz your_cool_app param1 param2

You can test buzz by running his the app `buzz_test`:

buzz_test

`buzz_test` runs the app `smarty_pants` that spews out random facts to you and
taunts you. Occasionally `smarty_pants` will commit suicide, but buzz will
bring him back to life.

`buzz_test` ends up actualy just running the following command:

buzz 10 smarty_pants 2000 0.15

Which will kill smarty pants every 10 seconds and bring him back to life. Also,
every two seconds, smarty pants will spit out a random fact. Approximately, every
13 seconds smarty pants will take his own life, but Buzz will bring him back.

Motivation

I have a command line app that is nasty to debug. It’s working fine for the first
five minutes or so. Thus, Buzz was born. Instead of fixing the bug, I wanted
to make this. =)

But really, it’s utility is that it’s a much simpler Forever.

The name comes from Buzz Lightyear in the movie Toy Story. His popular phrase was: To infinity and beyond!

Do you use Git? If so, checkout Gitpilot to make using Git thoughtless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Follow

Get every new post delivered to your Inbox.