1. Trang chủ
  2. » Công Nghệ Thông Tin

Lập trình Wrox Professional Xcode 3 cho Mac OS part 70 pdf

8 160 0
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 8
Dung lượng 2,8 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Instead, the unit test bundle ’ s code links directly to the functions defi ned in the application and executes all of the tests.. Except for those confi guration differences, you can fo

Trang 1

at run time The settings instruct the loader to fi rst load a special unit test framework into the

application ’ s address space This process is known as bundle injection The testing framework

causes your unit test bundle to also be loaded into memory Initialization code in your unit test bundle intercepts the execution of your application, preventing it from running normally Instead, the unit test bundle ’ s code links directly to the functions defi ned in the application and executes all

of the tests It then forces the application to terminate

However convoluted, the beauty of this process is that your unit tests will test the actual, binary code of your application; the same code that will run when your application launches normally

The disadvantage is that this process is complex and requires a number of concessions from your application Mostly these are restrictions on how your application is built In the case of some C/C++ applications, you are also required to add code to your application to support dependent unit testing

iPhone Unit Tests

The iPhone SDK supports unit testing too The techniques are very similar to the Objective - C unit testing under Mac OS X — in fact, they both use the same testing framework — but with the following differences:

Independent unit tests are called logic tests in iPhone parlance, and are executed using the

iPhone simulator

Dependent unit tests are called application tests in iPhone parlance, and are preformed on

an actual iPhone or iPod Touch

Setting up an application test suite for the iPhone is signifi cantly different than setting up a dependent test suite for a Mac OS X application

Except for those confi guration differences, you can follow the guidelines and instructions for writing Objective - C unit tests when developing for the iPhone, substituting the terms “ independent test ” and “ dependent test ” with “ logic test ” and “ application test ”

iPhone unit testing requires iPhone OS 3.0 or later.

ADDING A UNIT TEST TARGET

The fi rst step in adding unit testing to a project is to create a unit test target Choose Project ➪ New Target and choose a Unit Test Bundle template Choose the Unit Test Bundle template from the Carbon group to test a C/C++ product, from the Cocoa group to test a Mac OS X Objective

-C product, or from the -Cocoa Touch group to create an iPhone unit test An example is shown in Figure 20 - 2

Download at getcoolebook.com

Trang 2

Some releases of the Xcode Development Tools, particularly those intended for iPhone development, do not include the older Carbon and C++ target templates,

so your installation might not have a Carbon Unit Test Bundle template

You can “borrow” one from an older Xcode installation or try installing the Mac OS X Xcode package.

Give the target a name and select the project it will be added to Choose a name that refl ects the

subject of the test For example, if you were writing tests for a target named HelperTool , you might

name the unit test target HelperToolTests

FIGURE 20 - 2

Xcode creates a new unit test target and adds it to your project You now need to confi gure it

properly and populate it with tests How you confi gure your unit test target depends on what kind

of unit test it is and what kind of product it tests

You might be anxious to try out your new unit test target, but you can ’ t until

it is confi gured and you have added at least one test; a unit test bundle will fail

if it doesn ’ t contain any tests The “ Creating a Unit Test ” section, later in this chapter, tells you how to add tests to your unit test bundle.

Trang 3

Unit Test Target Dependencies

Unit tests are part of the build process Target dependencies are used to integrate unit tests into your build What target dependencies you create (if any) will depend on the kind of unit test you are creating

Independent Unit Test Dependencies

Because independent/logic unit tests are self - contained, they do not (technically) need to be dependent on any other targets All of the code that needs to be tested will be compiled when the target is built Whenever you want to run your unit tests, simply build your unit test target

One of the main tenets of test driven development is that your unit tests should be performed automatically every time you build your project To do that, follow these steps:

1. Set the active target to your application target

2. Make your application target dependent on your unit test target

Now every time you build your application, Xcode will fi rst build and run all of the unit tests

Alternatively, you could make the unit test target dependent on your application target; then you have the choice of just building your application or building your application and running all

of your unit tests You could also leave your application and unit test targets independent of each other and create an aggregate target that builds both As you can see, independent unit test targets are pretty fl exible

Dependent Unit Test Dependencies

Dependent Mac OS X (but not iPhone) unit test targets must depend on the target, or targets, that produce the products they test Otherwise, there is no guarantee that the tests will be performed

on up - to - date code If you want unit tests run every time you build your product, follow these steps:

1. Set the active target to the unit test target

2. Set the active executable to the results of the product target

Now every time you build, the application is built followed by a run of all of the unit tests The build will only be successful if both the build and the unit tests pass muster

Using this arrangement, you can easily ignore unit tests by building just the product target, or making another target dependent on the product target directly In a project with many product and unit test targets you could, for example, create two aggregate targets: one that depends on all

of the product targets for “ quick ” builds and a second that depends on all of their respective unit test targets for “ full ” builds

An iPhone unit test target ’ s dependencies are inverted from those used by dependent unit test targets The section “ Confi guring an iPhone Application Test ” shows you both how to confi gure the iPhone application unit test target and set up its dependencies

Download at getcoolebook.com

Trang 4

Confi guring an Independent/Logic Unit Test

Independent unit tests require no special confi guration All you need to do is make the source

code for both the tests and the code to be tested members of the target The compiler build settings

for the target should match those of your product target as closely as possible, so that the code

produced when you ’ re compiling the unit test target is as close as possible to the code that will be

compiled into your fi nal product

Add the source fi les to the target by dragging them into the Compile Sources phase of the unit test

target, or by opening their Info window and adding them to the unit test target in the Targets tab

You can add the source for the actual tests in a similar manner (if the tests already exist), or by

adding them to the unit test target when you create them The section “ Creating a Unit Test ” shows

how to write and add a new test

The target SDK for an iPhone logic test (independent unit test) must be set to the iPhone Simulator

Confi guring a Mac OS X Dependent Unit Test

A dependent unit test needs to know where to load the application or libraries to be tested

Testing an Application

For applications, you accomplish this by setting the Bundle Loader ( BUNDLE_LOADER ) and Test Host

these steps to quickly set both values:

1. In the Info window of the unit test target, select the Build tab Choose All Confi gurations

Arrange the windows so that Groups & Files list in the project window and the Info window are both visible Expand the Products group in the project source group

2. In the target ’ s Info window, fi nd the Bundle Loader setting — you ’ ll fi nd it in the Linking

group — and click in its value fi eld to edit it In the Products smart group, locate the executable product to be tested and drag it into the value fi eld of the Bundle Loader setting

Xcode inserts the full path to the executable For application bundles, you need to locate the application ’ s binary executable — the folder with the extension .app is not an executable

You can manually supply the path, or follow these steps:

a. Right/Control+click the product and choose Reveal in Finder

b. In the Finder, Right/Control+click the application and choose Open Package Contents

c. Open the Contents folder

d. Open the MacOS folder

e. Drag the application ’ s executable into the Bundle Loader setting ’ s value cell in the target ’ s Info window

3. Select the beginning of the path that represents the build location for the current build

confi guration Typically this is / path/to/project - folder /build/ build - configuration

Trang 5

this portion of the path with the $(CONFIGURATION_BUILD_DIR) macro In a project that produces a simple command - line executable, the fi nal Test Host path will look like

the Bundle Loader path will look something like $(CONFIGURATION_BUILD _DIR)/ AppName

4. Locate the Test Host setting — you ’ ll fi nd it in the Unit Testing group — and double - click its value fi eld to edit it Enter $(BUNDLE_LOADER) as its value This sets the TEST_HOST build setting to the same value as the BUNDLE_LOADER setting

The Bundle Loader setting tells the linker to treat the executable as is if were a dynamic library

This allows the tests in the unit test bundle to load and link to the classes and functions defi ned in your application

The Test Host setting tells the unit test target ’ s script phase the executable that will initiate testing

When testing an application, it is the application that gets loaded and launched The injected testing framework and bundle intercepts the application ’ s normal execution to perform the tests

Preparing Your Application

A few concessions are required of applications being tested by dependent unit test bundles You must make these changes in the target that produces your application, not the unit test target These requirements do not apply to independent unit tests or when you ’ re testing dynamic libraries or frameworks

Open the Info window for the application target and choose the Build tab Choose All Confi gurations and set the following:

Set ZeroLink to NO (uncheck the box)

If your project is a C++ program, fi nd the Symbols Hidden By Default setting and turn it off (uncheck the box)

ZeroLink must be turned off for your application The ZeroLink technology is incompatible with the techniques used to intercept the application at run time ZeroLink has been deprecated in Xcode 3, so you may not even see it in your build settings, but projects from prior versions of Xcode may still have it set

The Symbols Hidden By Default option must be disabled for C++ applications so that all of the classes and functions defi ned by your application appear as external symbols The unit test target must link to the symbols in your application, so these symbols must all be public Objective - C tests are all resolved at run time by introspection, so they don ’ t require any public symbols at link time

Testing Libraries and Frameworks

When you ’ re constructing a unit test to test a dynamic library or framework, leave the Bundle Loader and Test Host settings empty This is because the “ program ” to be loaded for testing will

be the unit test bundle itself If the Test Host setting is blank, the script launches the otest (for Objective - C) or CPlusTestRig (for C/C++) tool instead The testing tool loads the unit test bundle and runs the tests it fi nds there, with the assumption that the unit test bundle either contains (in the

Download at getcoolebook.com

Trang 6

case of independent tests) or will load (in the case of dependent tests for libraries and frameworks)

the code to be tested

For dependent unit tests that test libraries or frameworks, the unit test bundle is the client

application Confi gure your unit test bundle exactly as you would an application that uses those

libraries or frameworks, adding the frameworks to the target and including whatever headers are

appropriate to interface to them The dynamic library loader takes care of resolving the references

and loading the libraries at run time

Confi guring an iPhone Application Test

Testing an iPhone application is different from testing a Mac OS X application, and requires a

different organization in Xcode In Mac OS X development (described in the previous section), you

tell the unit test bundle what product you want tested It takes on the responsibility of loading that

target, injecting itself into the application, and performing its tests

In iPhone development, the roles of the application and unit test bundle are reversed You create a

custom version of your application that includes the unit test bundle product You load and run your

test app on your iPhone or iPod Touch device like any other app Once started, your app loads the

unit test bundle, which takes over and performs its tests

To confi gure an iPhone app for unit testing, follow these steps:

1. Add a Unit Test Bundle target, using the Cocoa Touch Unit Test Bundle template, as

described in the beginning of this section This is your unit test target

2. Duplicate the target that builds your app Give it a descriptive name like MyAppTesting

This is your test app target

3. Make your test app target dependent on your unit test bundle target

4. Add the product of the unit test target (the MyTests.octest bundle) to the Copy Bundle

Resources phase of your test app target This will include the compiled suite of unit tests in your app ’ s resource bundle

5. Set the active target to the test app target

6. Set the Target SDK to iPhone Device 3.0 or later

7. Build and run your test app target The test results will appear in your console window

Unlike all other kinds of unit tests, iPhone application tests aren ’ t run during the build phase You

must build and run your test application, which downloads both it and the unit tests to your iPhone

for execution This introduces a number of limitations to using iPhone application tests:

Application tests can ’ t be made an automatic part of your build process

The application test bundle must also be provisioned to run on your iPhone The “ correct ” way to do this is to create a provisioning profi le that includes both the application and the application test bundle (see Chapter 22) I admit that I ’ ll often simply set the Bundle

Trang 7

Identifi er build setting in the unit test bundle to the same ID as the application It seems sleazy, but it works

The unit test bundle will take over your app, run its tests, and exit You can ’ t use your application interactively during testing

The code in the unit test can ’ t link directly to the application This is because the unit test target builds before the application, so it can ’ t link directly to the application ’ s code

You might be scratching your head about the last one You ’ re probably asking “ If the unit test code can ’ t link to the code in the application, what use is it? ”

One solution is to include the code in both targets At run time only one implementation of the class will be used — most likely the one in the application (because it loaded fi rst), but the Objective - C run time doesn ’ t specifi cally guarantee this Regardless, this is an acceptable solution

in most cases and gives your unit tests direct access to iPhone hardware and its application environment

Another solution is introspection Instead of referring to application classes directly, do it indirectly

in the case where the test will be running on an actual iPhone Listing 20 - 1 shows an example This code will compile, link, and run — as long as something in the same process actually implements the SieveOfEratosthenes class, which our application does

- (void)setUp {

#if TARGET_OS_IPHONE testSieve = [[NSClassFromString(@"SieveOfEratosthenes") alloc]

initWithMaxPrime:UNIT_TEST_MAX_PRIMES];

#else testSieve = [[SieveOfEratosthenes alloc]

initWithMaxPrime:UNIT_TEST_MAX_PRIMES];

#endif STAssertNotNil(testSieve,@"Unable to create SieveOfEratosthenes");

}

The most signifi cant pitfall in iPhone application testing is the same problem inherent in logic tests (independent unit tests) Namely, that you run the risk

of testing code that’s different from the code in your fi nal product You must remember to update your test app target scrupulously so that it has the same build confi guration as your primary app target If you have any doubts, simply discard the test app target and reproduce it using the steps listed previously This will guarantee that all of your test app target settings are identical to those in your production app target

Download at getcoolebook.com

Trang 8

CREATING A UNIT TEST

Once you have your unit test target created and confi gured, adding unit tests is simple Here are the

basic steps:

1. Create a unit test class and add its source fi le to the unit test target

2. Add test methods to the class

3. Register the tests with the unit testing framework

Unit test class fi les can go anywhere in your project, but I suggest, at the very least, creating a group

for them named “ Tests ” or “ Unit Tests ” In a larger project you might organize your unit test fi les in

a folder, or you might group them together with the code that they test The choice is yours

Each class that you create defi nes a group of tests Each test is defi ned by a test method added to

the class A class can contain as many different tests as you desire, but must contain at least one

How you organize your tests is entirely up to you, but good practices dictate that a test class should

limit itself to testing some functional unit of your code It could test a single class or a set of related

functions in your application

Once defi ned, your tests must be registered with the unit testing framework so that it knows what tests

to run For Objective - C tests this happens automatically Objective - C test methods must adhere to a

simple naming scheme — basically they must all begin with the name “ test ” Objective - C introspection

is then used to locate and run all of the tests you defi ned For C++ unit tests, you add a declaration for

each test you ’ ve written The exact requirements for each are described in the “ Objective - C Tests ” and

“ C++ Test Registration ” sections, respectively

Each test method should perform its test and return Macros are provided for checking the

expectations of each test and reporting failures A test is successful if it completes all of its tests and

returns normally An example test is shown in Listing 20 - 2

void SieveOfEratosthenesTests::testPrimes( )

{

// Test a number of known primes

static int knownPrimes[] =

{ 2, 3, 5, 11, 503, 977, 12347, 439357, 101631947 };

SieveOfEratosthenes testSieve(UNIT_TEST_MAX_PRIMES);

CPTAssert(testSieve.isPrime(knownPrimes[i]));

}

In this example, the testPrime function defi nes one test in the SieveOfEratosthenesTests class The

test creates an instance of the SieveOfEratosthenes class, and then checks to see that it correctly

identifi es a series of numbers known to be prime If all of the calls to testSieve.isPrime() return

true , the test is successful; the testPrimes object is destroyed and the function returns If any call

that the test failed The testing macros are described in the “ Objective - C Test Macros ” and “ C++

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

TỪ KHÓA LIÊN QUAN