{"id":20,"date":"2005-07-23T18:02:51","date_gmt":"2005-07-24T02:02:51","guid":{"rendered":"http:\/\/eschatologist.net\/blog\/?p=20"},"modified":"2009-01-25T19:34:48","modified_gmt":"2009-01-26T03:34:48","slug":"xcode-debugging-cocoa-framework-unit-tests","status":"publish","type":"post","link":"https:\/\/eschatologist.net\/blog\/?p=20","title":{"rendered":"Xcode: Debugging Cocoa framework unit tests"},"content":{"rendered":"<p>So you&#8217;ve <a href=\"http:\/\/chanson.livejournal.com\/119303.html\">set up unit testing for your Objective-C Cocoa framework<\/a> and it&#8217;s been working great.  But now you&#8217;ve written a test and it fails, and you can&#8217;t figure out why.  It&#8217;s time to break out the debugger, but how, exactly, do you do that?  Your unit tests are built as a bundle, and you can&#8217;t <em>run<\/em> a bundle.<\/p>\n<p>It&#8217;s simple.  All you have to do is set up an appropriate <strong>Executable<\/strong> in Xcode to run the test rig that runs your bundle, and then debug that.  To get started, choose the <strong>Project > New Custom Executable<\/strong> menu item.  For its name, specify <code>otest<\/code> \u00e2\u20ac\u201d this is the name of the <em>test rig<\/em> used by OCUnit.  Specify <code>\/Developer\/Tools\/otest<\/code> as the path to your tool.<\/p>\n<p>When you add the custom executable, Xcode will bring up its info window.  Switch to the <strong>Arguments<\/strong> tab.  Here you&#8217;ll need to enter some command-line arguments to pass to the test rig and some environment variables to affect how it&#8217;s run.<\/p>\n<p>First, add the argument <code>-SenTest Self<\/code> to your executable.  This tells <code>otest<\/code> to run all of the tests in your bundle.  (It&#8217;s actually a pair of arguments, but you can add it as one as a convenience.)  Then for your second argument specify <code>$(BUILT_PRODUCTS_DIR)\/<i>MyTestBundle<\/i>.octest<\/code> where <i>MyTestBundle<\/i> is the name of your test bundle.  This tells <code>otest<\/code> the path of the test bundle to load; <code>$(BUILT_PRODUCTS_DIR)<\/code> will be expanded to the appropriate build products directory for your project at run time.  (If you get the order wrong, just drag the arguments around in the table.)<\/p>\n<p><strong>Troubleshooting note:<\/strong>  If this doesn&#8217;t work \u00e2\u20ac\u201d that is, if <code>otest<\/code> complains it can&#8217;t find your test bundle \u00e2\u20ac\u201d change the executable&#8217;s working directory (in the <strong>General<\/strong> tab) to Built Products Directory and <em>remove<\/em> <code>$(BUILT_PRODUCTS_DIR)<\/code> above.  Generally this is caused by <code>$(BUILT_PRODUCTS_DIR)<\/code> not being expanded to a full path, but rather to a partial path relative to your project directory.<\/p>\n<p>Next add a pair of environment variables named <code>DYLD_FRAMEWORK_PATH<\/code> and <code>DYLD_LIBRARY_PATH<\/code> to your executable.   These will tell the loader to check your build products directory first for frameworks and libraries whenever the executable is run from within Xcode.  Specify <code>$(BUILT_PRODUCTS_DIR)<\/code> for the value of each variable.<\/p>\n<p>Finally, from the <strong>Project > Set Active Executable<\/strong> menu choose your new <strong>otest<\/strong> executable.  This way any time you run or debug within Xcode, it will run <code>otest<\/code> with the arguments and environment you&#8217;ve specified.<\/p>\n<p>To actually debug a failing test, build your tests and set a breakpoint on the line where the failure occurs.  Now choose <strong>Debug Executable<\/strong> from the <strong>Debug<\/strong> menu.  <em>Do not choose <strong>Build and Debug<\/strong> from the <strong>Build<\/strong> menu.<\/em>  You need to use <strong>Debug Executable<\/strong> because your build will fail due to the failing test; <strong>Debug Executable<\/strong> doesn&#8217;t try to build first, it only cares whether an executable is present.<\/p>\n<p>You should successfully stop at your breakpoint!<\/p>\n<p>If your tests take a long time to run \u00e2\u20ac\u201d they shouldn&#8217;t, they&#8217;re unit tests after all, but it can still happen \u00e2\u20ac\u201d you may want to just run the tests for one test case, or just one individual test.  This is easy too.  Rather than specifying <code>-SenTest Self<\/code> in your arguments to <code>otest<\/code>, you can specify <code>-SenTest <i>MyTestCaseClassName<\/i><\/code> to run the all the tests in the specified test case. To run just a single test, use <code>-SenTest <i>MyTestCaseClassName\/testMethodName<\/i><\/code> instead.<\/p>\n<p><strong>Update July 7, 2007:<\/strong> Added the troubleshooting note about removing <code>$(BUILT_PRODUCTS_DIR)<\/code> if you get errors about not being able to load the bundle.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So you&#8217;ve set up unit testing for your Objective-C Cocoa framework and it&#8217;s been working great. But now you&#8217;ve written a test and it fails, and you can&#8217;t figure out why. It&#8217;s time to break out the debugger, but how, exactly, do you do that? Your unit tests are built as a bundle, and you&hellip;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[3],"tags":[9,20,18,7,17],"class_list":["post-20","post","type-post","status-publish","format-standard","hentry","category-technology","tag-cocoa","tag-debugging","tag-objective-c","tag-unit-testing","tag-xcode"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p74loH-k","_links":{"self":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/20","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=20"}],"version-history":[{"count":3,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/20\/revisions"}],"predecessor-version":[{"id":23,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=\/wp\/v2\/posts\/20\/revisions\/23"}],"wp:attachment":[{"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=20"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=20"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eschatologist.net\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=20"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}