开发者

How can I run OCUnit (SenTestingKit) with NSDebugEnabled, NSZombieEnabled, MallocStackLogging?

I have an error similar to the one in this post. Now, I'm sure I've made some stupid error somewhere, probably related to releasing an object or an observer or what-not, but since I can't seem to find a way to debug the code I thought I could use the NSDebugEnabled, NSZombieEnabled and MallocStackLogging (as shown here).

Can it be done using OCUnit? If so, how? I just can't find an "executable" to set these parameters on...

Thanks! Aviad开发者_如何学运维.


Unfortunately, Dave's solution didn't work - I kept getting errors and mistakes. I eventually got GHUnit to work on my project, found the problem by debugging, but it had its own problems so I now use both it and OCUnit which is slightly better integrated in terms of showing the results in the results tab.

sigh. When will we get to see a good, complete unit testing framework for Obj-C?


This may have been fixed in recent Xcodes, but I get zombies by doing

  1. Go into schemes (cmd <)
  2. Open Test, then Arguments tab
  3. Uncheck "Use the Run action's arguments and environment variables"
  4. "+" an environment variable "NSZombieEnabled" = "YES"


Well, NSZombieEnabled and friends are environment variables, which means they have to be run on an executable. The default setup for a unit testing bundle is for the tests to be run during the build process, and not during execution.

So the way to fix this is to make it so that your tests don't run during the build phase, but instead run them as part of an executable.

Here's how I do that:

  1. Inside your Unit Test bundle target, remove the "Run Script" build phase. It's that step that executes the tests after compiling them.
  2. From the Project menu, choose "New Custom Executable..." and name it something meaningful, like "otest"
  3. Make the executable path to be the otest binary, which should be located at /Developer/Tools/otest
  4. Set the following environment variables on the otest executable:
    • DYLD_FRAMEWORK_PATH => {UnitTest.bundle}/Contents/Frameworks
    • DYLD_LIBRARY_PATH => {UnitTest.bundle}/Contents/Frameworks
  5. Set the following program arguments on the otest executable:
    • -SenTest All (this will run all of the unit tests)
    • {UnitTest.bundle}

You can now select your unit test bundle as the active target, and the otest executable as the active executable, and then build and debug. This will let you set breakpoints, set other environment variables (like NSZombieEnabled), and so on.

If you only want to debug a certain suite or specific unit test, you can change the -SenTest All argument to -SenTest MyUnitTestSuite or -SenTest MyUnitTestSuite/myUnitTestMethod.


It took me quite some time but I finally managed to make it work for my project. To create the "logic" tests I followed Apple guidelines on creating logic tests. This works fine once you understand that the logic tests are run during build.

To be able to debug those tests it is required to create a custom executable that will call those tests. The article by Sean Miceli on the Grokking Cocoa blog provides all the information to do this. Following it however did not yield immediate success and needed some tweaking.

I will go over the main steps presented in Sean's tutorial providing some "for dummies" outline which took me some time to figure out:

  1. Setup a target that contains the unit tests but DOES NOT run them
  2. Setup the otest executable to run the tests
  3. Setup the otest environment variables so that otest can find your unit tests

Step 1 - Setting up the target

  1. Duplicate your unit tests target located under your project Targets. This will also create a duplicate of your unit tests product (.octest file). In the figure below "UnitTest" is the original target.
  2. Rename both the unit tests target and the unit tests product (.octest file) to the same name. In the figure below "UnitTestsDebug" is the duplicate target.
  3. Delete the RunScript phase of the new target

The name of both can be anything but I would avoid spaces.

Step 2 - Setting up otest

The most important point here is to get the correct otest, i.e. the one for your current iOS and not the default Mac version. This is well described in Sean's tutorial. Here are a few more details which helped me setting things right:

  1. Go Project->New Custom Executable. This will pop open a window prompting you to enter an Executable Name and an Executable Path.
  2. Type anything you wish for the name.
  3. Copy paste the path to your iOS otest executable. In my case this was /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest
  4. Press enter. This will bring you to the configuration page of your executable.
  5. The only thing to change at this point is to select "Path Type: Relative to current SDK". Do not type in the path, this was done at step 3.

Step 3 - Setting up the otest arguments and environment variables

The otest arguments are straightforward to setup... But this proved to be my biggest problem. I initially had named my logic test target "LogicTests Debug". With this name and "LogicTests Debug.octest" (with quotes) as argument to otest I kept having otest terminating with exit code 1 and NEVER stopping into my code...

The solution: no space in your target name!

The arguments to otest are:

  1. -SenTest Self (or All or a test name - type man otest in terminal to get the list)
  2. {LogicTestsDebug}.octest - Where {LogicTestsDebug} needs to be replaced by your logic test bundle name.

Here is the list of environment variables for copy/pasting:

  • DYLD_ROOT_PATH: $SDKROOT
  • DYLD_FRAMEWORK_PATH: "${BUILD_PRODUCTS_DIR}: ${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}"
  • IPHONE_SIMULATOR_ROOT: $SDKROOT
  • CFFIXED_USER_HOME: "${HOME}/Library/Application Support/iPhone Simulator/User"
  • DYLD_LIBRARY_PATH: ${BUILD_PRODUCTS_DIR}:${DYLD_LIBRARY_PATH}
  • DYLD_NEW_LOCAL_SHARED_REGIONS: YES
  • DYLD_NO_FIX_PREBINDING: YES

Note that I also tried the DYLD_FORCE_FLAT_NAMESPACE but this simply made otest crash.

Step 4 - Running your otest executable

To run your otest executable and start debugging your tests you need to:

  1. Set your active target to your unit test target (LogicTestsDebug in my case)
  2. Set your active executable to your otest executable

You can build and run your executable and debug your tests with breakpoints.

As a side note if you are having problems running your otest executable it can be related to:

  1. Faulty path. I had lots of problem initially because I was pointing to the mac otest. I kept crashing on launch with termination code 6.
  2. Faulty arguments. Until I removed the space from bundle (.octest) name I kept having otest crash with exit code 1.
  3. Wrong path in environment variables. [Sean tutorial][8] has lots of follow-up questions giving some insight on what other people tried. The set I have now seems to work so I suggest you start with this.

You may get some message in the console which might lead you to think something is wrong with your environment variables. You may notice a message regarding CFPreferences. This message is not preventing the tests from running properly so don't focus on it f you have problems running otest.

Last once everything is working you will be able to stop at breakpoints in your tests.

One last thing...

I've read on many blogs that the main limitation of the integrated XCode SenTestKit is that tests cannot be run while building the application. Well as it turns out this is in fact quite easy to manage. You simply need to add your Logic tests bundle as a dependency to your application project. This will make sure your logic tests bundle is built, i.e. all tests are run, before your application is built.

To do this you can drag and drop your logic test bundle onto your application target.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜