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.
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.
Mount the package and extract the Source and Release directories.
Navigate to Source/ocmock-1.77 and open up OCMock.xcodeproj
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
Notice how there are 4 projects schemes: OCMockPhoneSim,
OCMockPhoneDevice, OCMock, and OCMockLib
Notice how there are four products: OCMock.framework,
OCMockTests.octest, libOCMock.a, and libOCMock.a
Recall, that we are most interested in a 64 bit libOCMock.a
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.
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.
Change Architecture to 64-bit on every drop down that you can.
Remove i386 from Valid Architecture.
Change scheme to "OCMockLib - My Mac 64-bit"
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"
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.
Open Xcode. Click File...New Project. Select Cocoa Application.
Name it whatever you want. Make sure that you click "Include Unit
Tests"
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.
Navigate to your project directory. Create a directory in it called
'TestLibraries'
Copy libOCMock.a and the folder 'OCMock' containing the header files
into the 'TestLibraries' directory.
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..'
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.
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"
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.
In the Test target build settings, locate 'Other Linker Flags', add:
-ObjC -all_load
In your implementation test file, locate the textExample method. Put
this snippet in its place:
#include<OCMock/OCMock.h>//put this at the topidmockString=[OCMockObjectmockForClass:[NSStringclass]];[[[mockStringstub]andReturn:@"MOCKS UP IN"]lowercaseString];STAssertEqualObjects([mockStringlowercaseString],@"MOCKS UP IN",nil);
Click "Product" menu and "Build For Testing"
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'