Lập trình Wrox Professional Xcode 3 cho Mac OS part 72 pot

5 123 0
Lập trình Wrox Professional Xcode 3 cho Mac OS part 72 pot

Đang tải... (xem toàn văn)

Thông tin tài liệu

572 ❘ CHAPTER 20 UNIT TESTING The static constructor for installTimer causes an instance of this object to be created during the initialization of your application. Because the constructor is part of the code in the unit test, the UnitTestRunner object is only created when your application is running in the presence of the unit test bundle. The class creates a timer with a 0 interval and registers it with the Carbon event manager. As soon as the application has performed its basic initialization and the event loop is ready to run, the timer fi res. The testTimerFired() function catches the timer event and invokes the runTests() function. This function runs all of your unit tests and quits the application. In the absence of the unit test bundle, there is no constructor, no timer object is created, and your application starts running normally. The beauty of this scheme is that it requires no modifi cation to your application. There is no possibility of accidentally producing a version of your application that contains any unit test support, and you can test the fi nal application binary you intend to release. DEBUGGING UNIT TESTS Who watches the watchers? Sometimes a unit test, designed to keep your application free of bugs, has bugs itself. When this occurs, you need to bring the power of the debugging tools to bear on the unit test code, rather than your application. The problem is that unit tests run during the build phase, not the debug phase, of the Xcode environment. The tests themselves are never the target of a Debug or Run command, and you have the added catch - 22 of trying to build an application whose unit tests fail. Debugging iPhone Application Tests However awkward an iPhone application (dependent) unit test is to set up and use, it is stunningly simple to debug. Remember that an iPhone application test is a regular copy of your iPhone app that includes a unit testing bundle. To debug your application tests, simply run your test application target under the control of the debugger (Run ➪ Debug). Figure out what ’ s wrong and then return to running your application normally. Debugging Dependent Mac OS X Unit Tests Debugging dependent unit tests for an application requires that you reverse the normal order of targets and trick the application target into running your unit tests instead of executing your application normally, all under the control of the debugger. Here ’ s how: 1. Open the Info window for the project (Project ➪ Edit Project Settings). In the General tab, change the Place Intermediate Build Files In setting to Build Products Location. 2. Remove the application target dependency from the unit test target. 3. Set the active target to the application target and build it (Build ➪ Build). 4. Add the unit test target as a dependency for the application. This reverses the normal dependency between the unit test and the target. c20.indd 572c20.indd 572 1/22/10 4:17:26 PM1/22/10 4:17:26 PM Download at getcoolebook.com 5. Disable the run script phase of the unit test target. Expand the dependent unit test target and double - click the fi nal run script phase. Edit the script by adding an exit command at the beginning, as shown in Figure 20 - 5, essentially disabling the script. 6. Open the Info window for the application ’ s executable (in the Executable smart group). Select the Arguments tab. If this is an Objective - C application, add the argument - SenTest All . 7. In the environment variables pane: a. Add a DYLD_INSERT_LIBRARIES variable and set its value to $(DEVELOPER _LIBRARY_DIR)/PrivateFrameworks/DevToolsBundleInjection .framework/DevToolsBundleInjection . b. Add a DYLD_FALLBACK_FRAMEWORK_PATH variable and set it to $(DEVELOPER _LIBRARY_DIR)/Frameworks . c. Add an XCInjectBundle variable and set it to UnitTestBundlenName .octest . If this is a C++ testing bundle, the extension will be .cptest instead of .octest . d. Add an XCInjectBundleInto variable and set it to AppName . app/Contents/MacOS/ AppName . 8. Your application executable should now look like the one in Figure 20 - 6. Set your active build confi guration to Debug. FIGURE 20 - 5 FIGURE 20 - 6 Debugging Unit Tests ❘ 573 c20.indd 573c20.indd 573 1/22/10 4:17:27 PM1/22/10 4:17:27 PM Download at getcoolebook.com 574 ❘ CHAPTER 20 UNIT TESTING 9. Add the statement set start - with - shell 0 to the invisible .gdbinit fi le in your home directory, creating the fi le if it doesn ’ t already exist. You can do this using a number of text editors (BBEdit, emacs, pico, and so on) or by issuing the following commands in a Terminal window: echo '' > > ~/.gdbinit echo 'set start-with-shell 0' > > ~/.gdbinit Now build and debug your project. The application target causes the unit tests target to build, but not run (because you disabled the unit test ’ s run script). Note that there ’ s a quirky circular dependency here — the unit test target still tries to link to your application ’ s binary. If your application hasn ’ t been built, the unit test target will fail to build with a link error. That ’ s why I had you perform step 3 before proceeding, so the unit test bundle has a product to satisfy its link phase. Xcode then launches the executable under the control of the debugger. The environment variables trick the application executable into acting as if it were being run for the purposes of unit testing. The system loads the unit test bundle and executes the tests, allowing you to set breakpoints in the unit test source and debug them. TIP TO REMEMBER There are so many steps involved in setting up a dependent unit test for debugging that it’s easy to mess up your project in the process. Before you begin, make a copy of your project document or check it into source control. After you’ve debugged your problem — and assuming that the fi x didn’t involve changes to your project document — simply discard the test document and replace it with the saved one. You should always close the project before copying, replacing, or renaming your project document. When you are done debugging your unit tests, reverse the entire process, as follows: 1. Reverse the dependencies so that the unit test target once again depends on the application target. 2. Remove or comment out the exit statement at the beginning of the unit test ’ s run script phase. 3. Disable the special arguments and environment variables in the application ’ s executable by removing the check mark next to each one. 4. Set your project ’ s Place Intermediate Build File In setting back to your original choice. 5. Remove the set start - with - shell statement in your ~/.gdbinit fi le. You can optionally just leave it, because it shouldn ’ t interfere with anything else in Xcode. c20.indd 574c20.indd 574 1/22/10 4:17:28 PM1/22/10 4:17:28 PM Download at getcoolebook.com Debugging Independent Unit Tests Debugging independent tests is a little simpler. It requires that you create an executable from the unit test bundle so that the debugger knows how to launch it under its control. The executable is actually the test harness utility and its arguments tell it what unit test bundle to load and execute. Follow these steps to create the executable: 1. Create a custom executable. Give it the same name as your independent unit test target. (The “ Custom Executables ” section in Chapter 18 has the details.) 2. Set the executable to $(DEVELOPER_TOOLS_DIR)/otest for Objective - C unit test bundles, or $(DEVELOPER_TOOLS_DIR)/CPlusTestRig for C++ unit test bundles. 3. In the Arguments tab, add the $(CONFIGURATION_BUILD_DIR)/ NameOfUnitTest .octest argument for Objective - C bundles. The bundle extension will be .cptest for C++ bundles. 4. Disable the unit tests in the independent unit test target by adding an exit statement to the beginning of the run script phase, as previously shown in Figure 20 - 5. Set the active target to the unit test and the active executable to the custom executable you just created. You can now set breakpoints in the unit tests and launch it under the control of the debugger just like any other application. When you are done debugging, restore the run script phase of the unit tests by removing the exit statement in the run script phase. This permits the tests to run during the build phase once again. SUMMARY Unit tests can be powerful allies. They permit you to codify the behavior of your code and integrate the validation of that behavior directly into the build process. Incorrect handling of a parameter value, or the failure to throw an exception under certain circumstances, is now as easily caught as syntax errors in your source code. Effective use of unit testing is a discipline, encompassing a variety of philosophies and a broad range of styles and techniques. If you are serious about integrating unit testing into your development, you should get a good book on test - driven design or Extreme Programming. Summary ❘ 575 c20.indd 575c20.indd 575 1/22/10 4:17:28 PM1/22/10 4:17:28 PM Download at getcoolebook.com c20.indd 576c20.indd 576 1/22/10 4:17:29 PM1/22/10 4:17:29 PM Download at getcoolebook.com . editors (BBEdit, emacs, pico, and so on) or by issuing the following commands in a Terminal window: echo '' > > ~/.gdbinit echo 'set start-with-shell 0' > > ~/.gdbinit. active build confi guration to Debug. FIGURE 20 - 5 FIGURE 20 - 6 Debugging Unit Tests ❘ 5 73 c20.indd 573c20.indd 5 73 1/22/10 4:17:27 PM1/22/10 4:17:27 PM Download at getcoolebook.com 574 ❘ CHAPTER. application. This reverses the normal dependency between the unit test and the target. c20.indd 572c20.indd 572 1/22/10 4:17:26 PM1/22/10 4:17:26 PM Download at getcoolebook.com 5. Disable the run script

Ngày đăng: 04/07/2014, 06:20

Tài liệu cùng người dùng

Tài liệu liên quan