Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Testing iPhone Code That Uses NSLocalizedString

I have an iPhone iOS4.1 application that uses localized strings. I have just started building unit tests using the SenTestingKit. I have been able to successfully test many different types of values.

I am unable to correctly test any of my code that uses NSLocalizedString calls, because when the code runs in my LogicTests target, all of my NSLocalizedString calls only return the string key.

I have added my Localizable.strings file to the LogicTests target.

My question is: How must I configure my LogicTests target so that calls to NSLocalizedString will return the localized string and not the string key.

like image 732
Jay Haase Avatar asked Sep 30 '10 17:09

Jay Haase


1 Answers

This problem was driving me crazy, but I was able to get NSLocalizedString to behave.

zoul was right, if you print the mainBundle to the console in a logic test, it's not the same bundle that contains your Localizable.strings file. You need to conditionally redefine NSLocalizedString whenever you run your unit tests. I did it in the following steps:

  1. We need a way to tell when we're in our logic tests target, so add something like LOGIC_TESTS to your logic tests target's Preprocessor Macros build setting.
  2. There's only 1 place in my code where I need to redefine NSLocalizedString, so I was able to place the following code in the header corresponding to that class. If you're having this problem in multiple places, I'd suggest putting the following code in a header and #include-ing it where you need it (I tried using a .pch file but it doesn't work in Logic Tests). Anyway, place this somewhere in the header of class(es) that use NSLocalizedString:

    #ifdef LOGIC_TESTS
    #undef NSLocalizedString
    #define NSLocalizedString(key, comment) [[NSBundle bundleWithIdentifier:@"YOUR_IDENTIFIER"] localizedStringForKey:(key) value:@"" table:nil]
    #endif
    

Replace YOUR_IDENTIFIER with the Bundle Identifier of your app's bundle (found in your Info.plist file, key is CFBundleIdentifier). This assumes that you've defined LOGIC_TESTS as a preprocessor macro only in your Logic Tests target.

edit: Curiously, once I removed some debugging code this solution stopped working. It looks like you have to trick Xcode into loading the bundle as well. The following does it:

NSString *path = @"path_to_main_bundle";
NSBundle *bundle = [NSBundle bundleWithPath:path];
NSLog(@"bundles: %@", [NSBundle allBundles]);

Where path_to_main_bundle is == [[NSBundle mainBundle] bundlePath] when you run your main target. Just log it once in gdb or using NSLog on your app delegate to grab the path. It should look something like /Users/YOUR_USER_NAME/Library/Application Support/iPhone Simulator/4.1/Applications/UUID_LOTS_OF_LETTERS_AND_NUMBERS_HERE/App.app.

I placed that code in the setUp call for one of my logic test classes. And no, I have no idea why I have to log allBundles to make it work, so anyone who has a clue, please let me know!

like image 92
kevboh Avatar answered Sep 20 '22 15:09

kevboh