在运行时更改iOS模拟器的当前区域设置

当开发一组date计算和语言规则来将数值和date转换为string时,我正在编写testing来断言string格式化方法的结果。 一个假想的断言可能看起来像这样:

NSAssert([dateString isEqualToString:@"Three days, until 6:00 PM"], @"Date string should match expectation"); 

但是,由于该应用程序已针对多种语言进行了本地化,而且我的开发人员也来自不同的语言环境,因此可能会发生这样的情况,即您的设备或模拟器被设置为与正在编写testing的语言环境不同的语言环境。 在这样的情况下, dateString的内容可能是这样的:

 @"Drie dagen, tot 18:00" // the assertion fails @"Drei Tage, bis 18 Uhr" // the assertion also fails 

这可能是也可能不是这些语言环境的正确date符号,但是我的问题的一部分是如何能够运行testing到特定的语言环境,当底层代码使用Apple API如下所示:

 [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterShortStyle]; 

我很想在我的断言中用两种或更多种语言来覆盖,就像这样:

 [NSSomething actionToSetTheLocaleTo:@"en_US"]; dateString = ...; // the formatting NSAssert([dateString isEqualToString:@"Three days, until 6:00 PM"], @"match en_US"); [NSSomething actionToSetTheLocaleTo:@"nl_NL"]; dateString = ...; // the formatting NSAssert([dateString isEqualToString:@"Drie dagen, tot 18:00"], @"match nl_NL"); 

谁知道如何达到这个效果?

笔记:

  • 改变首选语言不会削减它,它也需要影响NSDateFormatter和NSNumberFormatter的行为。
  • 因为这只是为了unit testing的目的,我会满足于使用私人API。 然而,为了别人的利益,在这篇文章中,公共API是首选。
  • 将自定义语言环境传递给每个date或数字格式API可能是最后的考虑因素,但是我发布了这个问题,希望避免回到那些极端的措施。 如果你知道这是唯一的解决scheme,请提供一些参考资料,我不会浪费更多的时间

关于主题的链接:

  • Ray Lillywhite在i18n和l10n的好文章
  • 关于NSLocale的NSHipster文章

@Desmond指出了一个可行的解决scheme。 直到他在这里把这个信息放在这里的答案,让我总结一下,我最终做了一些代码。

事实certificate,这个解决scheme与调用类方法在内部使用的方法 “一样简单”:

 beforeEach(^{ [NSBundle ttt_overrideLanguage:@"nl"]; [NSLocale ttt_overrideRuntimeLocale:[NSLocale localeWithLocaleIdentifier:@"nl_NL"]]; }); afterEach(^{ [NSLocale ttt_resetRuntimeLocale]; [NSBundle ttt_resetLanguage]; }); 

上面看到的ttt_...方法使用NSObject,NSLocale和NSBundle上的类别在运行时检查是否应使用原始方法或返回其他内容。 这个方法在编写testing的时候是完美无瑕的,尽pipe它在技术上并没有使用任何私有的API,但我强烈build议只在testing设置中使用它,而不是提交给App Store审查的任何东西。

在这个要点中,您会发现我添加到应用程序的testing目标中 的Objective-C类别,以实现所需的行为。

既然这是在一个unit testing,你有没有尝试在NSDateFormatter 设置区域设置 ? 您不必在整个模拟器上设置语言环境,您可以将其设置为testing的参数。 大多数依赖locale的cocoa方法可以把它作为参数或属性。

就像是:

 NSLocale *locale = [NSLocale localeWithLocaleIdentifier:@"en-US"]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setLocale:locale]; [formatter setDateStyle: NSDateFormatterNoStyle]; [formatter setTimeStyle: NSDateFormatterShortStyle]; [formatter setFormatterBehavior:NSDateFormatterBehavior10_4]; thing = [formatter stringForObjectValue:date]; 

您正在使用的localizedStringFromDate:dateStyle:timeStyle:方法logging在这里 ,除了语言环境以外,它都是非常明确的。 因此,您可以执行相同的步骤,但使用上述步骤将语言环境设置为系统当前语言环境以外的其他语言环境。

我看到的唯一方法就是冷静地提到。 但是,你提到它存在于很多地方。

而不是重写所有你现在的代码,你可以做一些奇特的事情

 #import "UnitTestDateFormatter.h" #define NSDateFormatter UnitTestDateFormatter 

然后简单地创build一个子类来处理它:

 @implementation UnitTestDateFormatter - (id) init { self = [super init]; if(self != nil) { [self setLocale:...]; } return self; } @end 

至less你的代码可以保持不变。