Tải bản đầy đủ (.pdf) (5 trang)

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

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (894.56 KB, 5 trang )

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

×