In unit test target, how do I get my orange breakpoints to be blue?
In unit test target, how do I get my orange breakpoints to be blue?
- Subject: In unit test target, how do I get my orange breakpoints to be blue?
- From: Pat McGee <email@hidden>
- Date: Mon, 08 Sep 2008 08:50:54 -0400
(Xcode 3.1, OS X 10.5.4)
I created a small Cocoa application with a WorkerBee class that had a
getAnswer method which returned an NSString*. Then I wrote a unit test
for it using the unit test bundle instructions and the code injection
instructions that Chris Hanson wrote.
I set a breakpoint in the unit test code and ran the unit test bundle
target. The breakpoint turned orange, and the debugger never stopped
there.
(The debugger console didn't show any error messages.)
Here's what I've tried so far:
1) In Xcode preferences: Debugging, turn off Load symbols lazily
2) Clean All targets
3) Restart Xcode.
According to several posts I've found, the first one should have
worked. So obviously I've done something wrong somewhere else that's
keeping it from working right. I haven't been able to figure out where
else to look.
Any hints of things I could try?
If you want to play around with the project file, it's here: http://xorandor.com/MyProject.tar
If you want to see all the steps of what I did, that's attached below
and here: http://xorandor.com/DebugQuestion.txt
Thanks,
Pat
1) In a new project, add an AppDelegate class, with one outlet and one action.
a) File: New Project: Application, Cocoa Application, "MyProject".
b) Right-click on Classes. Add: New File...: "Cocoa", "Objective-C class", "AppDelegate"
c) Add an outlet and an action to AppDelegate.h:
@interface AppDelegate : NSObject {
IBOutlet NSTextField *myLabel;
}
- (IBAction) clickMe: (id) sender;
@end
d) Add the action to AppDelegate.m:
- (void) clickMe: (id) sender
{
NSString *tempVar = @"42";
[myLabel setStringValue: tempVar];
}
e) Click Build.
2) In IB, instantiate an AppDelegate object, and make it the delegate of File's Owner. Connect a button to the action and a label to the outlet.
3) Make a WorkerBee class with a single method: getAnswer, that assigns a string to a temp var, and then returns the temp var.
a) Right-click Classes: Add: New File...: "Cocoa", "Objective-C class", "WorkerBee"
b) In WorkerBee.h, declare a method:
- (NSString *)getAnswer;
c) In .m, implement the method:
- (NSString *)getAnswer
{
NSString *tempAnswer = @"42";
return tempAnswer;
}
4) Modify AppDelegate to instantiate WorkerBee on init, then to get the string to put into the label from WorkerBee.
a) Here's the AppDelegate.h file:
#import <Cocoa/Cocoa.h>
@class WorkerBee;
@interface AppDelegate: NSObject {
WorkerBee *myWorkerBee;
IBOutlet NSTextField *myLabel;
}
- (IBAction) clickMe: (id) sender;
@end
b) And here's AppDelegate.m:
#import "AppDelegate.h"
#import "WorkerBee.h"
@implementation AppDelegate
- (id) init
{
[super init];
myWorkerBee = [[WorkerBee alloc] init];
return self;
}
- (void) clickMe: (id) sender
{
NSString * tempVar = [myWorkerBee getAnswer];
[myLabel setStringValue: tempVar];
}
@end
c) Click "Build and Go". Click the button and make sure you get 42.
5) Create a Unit Test Bundle to test WorkerBee and tell Xcode to run the tests each time it is built. (Following instructions from Chris Hanson's post: Unit Testing Cocoa Applications at http://chanson.livejournal.com/120263.html)
a) Right-click Targets. Add: New Target...: "Cocoa", "Unit Test Bundle", "RunWorkerBeeTests"
b) In the Target "RunWorkerBeeTests" Info window, add Direct Dependencies: MyProject, and close the window.
c) (Building the MyProject target should work. Building the RunWorkerBeeTests target should not work yet.)
d) Right-click the RunWorkerBeeTests target. Get Info. Click the Build tab.
e) Locate the "Linking" section and select the first property underneath it, "Bundle Loader". Set the value of the property to: "$(BUILT_PRODUCTS_DIR)/MyProject.app/Contents/MacOS/MyProject".
f) Locate the "Unit Testing" section and select the "Test Host" property. Set the value of the property to "$(BUNDLE_LOADER)". Note that this should change to expand the macro when you hit enter. The value should be "build/Debug/MyProject.app/Contents/MacOS/MyProject".
g) (At this point, Building the RunWorkerBeeTests target causes the app to run. Why? What can I do to make it not do that?)
6) Create a unit test case class. Put in a setup to instantiate WorkerBee. Add a unit test to store the result of a getAnswer call into a temp var, and then to test the result.
a) Right-click in Classes. Add: New File...: "Cocoa", "Objective-C test case class", "TestWorkerBee", add it to only RunWorkerBeeTests target, not MyProject.
b) Here's the code for TestWorkerBee.h:
#import <SenTestingKit/SenTestingKit.h>
@class WorkerBee;
@interface TestWorkerBee : SenTestCase {
WorkerBee *myWorkerBee;
}
@end
c) And here's the code for TestWorkerBee.m:
#import "TestWorkerBee.h"
#import "WorkerBee.h"
@implementation TestWorkerBee
- (void) setUp
{
myWorkerBee = [[WorkerBee alloc] init];
}
- (void) tearDown
{
[myWorkerBee release];
}
- (void) testWB1
{
NSString *thisAnswer = [myWorkerBee getAnswer];
STAssertEqualObjects (thisAnswer, @"42", @"What is the meaning of life?");
}
@end
d) (At this point, Build of the RunWorkerBeeTests should succeed.)
e) Change the value returned by getAnswer to @"41" and build the test target again. Verify that the build fails.
7) Tell Xcode to inject the test code (Using Chris Hanson's instructions from "Xcode: Debugging Cocoa application unit tests" at http://chanson.livejournal.com/120740.html
a) Locate the Executables smart group. Right-click on the MyProject entry, and select Get Info. In the Info window, click the Arguments tab.
b) Add an argument "-SenTest All"
c) Add environment variable DYLD_INSERT_LIBRARIES and set it to "$(DEVELOPER_LIBRARY_DIR)/PrivateFrameworks/DevToolsBundleInjection.framework/DevToolsBundleInjection"
d) Add environment variable XCInjectBundle and set it to "$(BUILT_PRODUCTS_DIR)/MyProject.octest".
e) Add environment variable XCInjectBundleInto and set it to "$(BUILT_PRODUCTS_DIR)/MyProject.app/Contents/MacOS/MyProject".
f) Add environment variable DYLD_FALLBACK_FRAMEWORK_PATH and set it to "$(DEVELOPER_LIBRARY_DIR)/Frameworks".
g) Close the window.
h) Build the Test target. Verify that it builds.
i) Build the app target. Verify that it builds.
j) Verify that "Build and Go" on the app target succeeds and that the app runs correctly.
k) +++ What should "Build and Go" on the test target do? It actually runs the app. I don't understand why it does that.
8) Turn off Load Symbols Lazily in Xcode preferences.
9) Verify that a break point set in WorkerBee is hit when running the MyProjects target and that a breakpoint set in TestWorkerBee is hit when running the RunWorkerBeeTests target:
a) Set a breakpoint on the return statement in getAnswer in WorkerBee.m. Set the target to "MyProject" and click "Build and Go". When the app comes up, click the button. Verify that it hits the breakpoint and stops.
b) Set a breakpoint on the STAssert statement in testWB1 in TestWorkerBee. Set the target to "RunWorkerBeeTests" and click "Build and Go". Verify that it hits the breakpoint in TestWorkerBee and stops.
c) +++ It doesn't stop at the breakpoint in TestWorkerBee. Instead it runs the app, just like clicking "Build and Go" with MyProject selected. When I click the button, it hits the breakpoint I set in WorkerBee.m, just like it did with the MyProject target selected.
--
"Save the Earth; it's the only planet with Chocolate!"
Pat McGee
email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden