Monday, August 10, 2009
down in the metal
I just wanted to say that I didn't think I would ever write low-level C code again. And yet, here I am:
(It's just a utility function to help populate a map with an assortment of randomly distributed pushpins, for test purposes. But still. Sheesh.)
+(NSNumber *) getRandomDoubleMin:(double)min max:(double)max {
srandomdev();
int nRange = (int) max-min;
int nRand = random() % nRange;
double dRand = (double) nRand;
dRand = dRand+min;
int nRand2 = random() %10000;
double dRand2 = (double)nRand2;
dRand2=dRand2/10000;
dRand=dRand+dRand2;
return [NSNumber numberWithDouble:dRand];
}
(It's just a utility function to help populate a map with an assortment of randomly distributed pushpins, for test purposes. But still. Sheesh.)
Monday, August 3, 2009
if you love some source code, set it free
So I have gone and
To be honest I would have liked another few days for cleanup and further testing, but I've gone and gotten a real job (iPhone app development, again) that will occupy me for at least a couple of months, so I had to hurry things up. I apologize for the ugliness of the code.
Some of that ugliness is due to its extremely crude testing framework. Unit testing, the panacea of modern software development, is bizarrely difficult to integrate with the iPhone SDK. There are various tools to help you - one created by Google - but they're all far more complex and kludgy than I'd like, especially compared to the elegant joy that is GAEUnit.
It turns out, however, that it is possible to seamlessly integrate unit tests and test-driven development into iPhone development with XCode. There are a few caveats, but overall, these instructions work very well, if you follow them very carefully.
The caveat is that you can only run the unit tests on an actual physical device, not in the simulator. Now, in some ways this is actually a bonus - you avoid the "but it works in the simulator!" pitfall, and I have learned that the only way to get a feel for what your UI should be is to work on a real iPhone or iPod Touch, the simulator is disastrously misleading - but it does mean that you'll have to go ahead and shell out the $100 to join the iPhone Developer Program so that you can generate the certificates needed to sign your app and install it on your device.
Which in turn is a bit of a hassle. But it's a necessary hassle, and one you should get out of the way as soon as possible. "Build early, build often," is a motto that has served me well for many years.
The device-testing is also limited in that you have to specifically select a test target, so you can't automatically run your unit tests every time you build your app. But as long as you remember to unit-test at least daily, and immediately after making major changes, I can't see this as that big a shortcoming.
Here's some code to run tests in their own separate database, so that you don't pollute your application's data.
Your test case's .h file looks something like this:
and its .m:
- a) officially submitted my Wikitravel-editor iPhone app to the App Store
- b) released its source code under a BSD open-source license for all to see and play with, at code.google.com/p/itravelwrite.
To be honest I would have liked another few days for cleanup and further testing, but I've gone and gotten a real job (iPhone app development, again) that will occupy me for at least a couple of months, so I had to hurry things up. I apologize for the ugliness of the code.
Some of that ugliness is due to its extremely crude testing framework. Unit testing, the panacea of modern software development, is bizarrely difficult to integrate with the iPhone SDK. There are various tools to help you - one created by Google - but they're all far more complex and kludgy than I'd like, especially compared to the elegant joy that is GAEUnit.
It turns out, however, that it is possible to seamlessly integrate unit tests and test-driven development into iPhone development with XCode. There are a few caveats, but overall, these instructions work very well, if you follow them very carefully.
The caveat is that you can only run the unit tests on an actual physical device, not in the simulator. Now, in some ways this is actually a bonus - you avoid the "but it works in the simulator!" pitfall, and I have learned that the only way to get a feel for what your UI should be is to work on a real iPhone or iPod Touch, the simulator is disastrously misleading - but it does mean that you'll have to go ahead and shell out the $100 to join the iPhone Developer Program so that you can generate the certificates needed to sign your app and install it on your device.
Which in turn is a bit of a hassle. But it's a necessary hassle, and one you should get out of the way as soon as possible. "Build early, build often," is a motto that has served me well for many years.
The device-testing is also limited in that you have to specifically select a test target, so you can't automatically run your unit tests every time you build your app. But as long as you remember to unit-test at least daily, and immediately after making major changes, I can't see this as that big a shortcoming.
Here's some code to run tests in their own separate database, so that you don't pollute your application's data.
Your test case's .h file looks something like this:
// Dependent unit tests mean unit test code depends on an application to be injected into.
// Setting this to 0 means the unit test code is designed to be linked into an independent executable.
#define USE_DEPENDENT_UNIT_TEST 1
#import <SenTestingKit/SenTestingKit.h>
#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
@interface MyTestCase : SenTestCase {
NSManagedObjectContext *context;
}
@end
and its .m:
-(void) setUp {
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSURL *storeUrl = [NSURL fileURLWithPath: [[appDelegate applicationDocumentsDirectory] stringByAppendingPathComponent: @"MyAppTest.sqlite"]];
NSError *error;
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [appDelegate managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
// Handle error
NSLog(@"Error creating persistent store MyAppTest.sqlite %@, %@", error, [error userInfo]);
}
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator: persistentStoreCoordinator];
}
-(void) tearDown {
[context release];
}
Labels: Apple, iPhone, testing, tests, unit, XCode
Subscribe to Posts [Atom]