14

在开发一组用于将数值和日期转换为字符串的日期计算和语言规则时,我正在编写测试来断言字符串格式化方法的结果。它的一个假想断言可能如下所示:

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

但是,由于该应用程序已针对多种语言进行了本地化,而且我的开发人员也来自与我不同的语言环境,因此您的设备或模拟器设置的语言环境可能与编写测试的语言环境不同。在这样的场景中, 的内容dateString可能类似于:

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

对于这些语言环境,这可能是也可能不是正确的日期表示法,但我的问题是关于如何在底层代码像这样使用 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 行为。
  • 因为这仅用于单元测试目的,所以我会满足于使用私有 API。但是,为了其他人在这篇文章中遇到的问题,公共 API 是首选。
  • 将自定义语言环境传递给每个日期或数字格式化 API 可能是最后的考虑因素,但我发布这个问题是希望避免回到那些极端措施。但是,如果您知道这是唯一的解决方案,请提供一些参考,我将不再浪费时间

主题链接:

4

3 回答 3

19

@Desmond 指出了一个可行的解决方案。在他在这里给出答案以输入此信息之前,让我总结一下我最终用一些代码所做的事情。

事实证明,该解决方案与调配类方法在内部使用的方法“一样简单” :

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

afterEach(^{
    [NSLocale ttt_resetRuntimeLocale];
    [NSBundle ttt_resetLanguage];
});

您在上面看到的ttt_...方法使用 NSObject、NSLocale 和 NSBundle 上的类别在运行时检查它是否应该使用原始方法或返回其他内容。在编写测试时,此方法完美无缺,虽然它在技术上不使用任何私有 API,但我强烈建议仅在您的测试设置中使用此方法,而不是用于您提交到 App Store 以供审核的任何内容。

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

于 2013-10-11T19:35:17.827 回答
3

由于这是在单元测试中,您是否尝试NSDateFormatter? 您不必在整个模拟器上设置语言环境,您可以将其作为测试的参数。大多数依赖于语言环境的可可方法都可以将其作为参数或属性。

就像是:

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];

您正在使用的本地化StringFromDate:dateStyle:timeStyle: 方法记录在此处,除了语言环境之外,它对所有内容都非常明确。因此,您可以执行相同的步骤,但使用上述步骤将语言环境设置为系统当前语言环境以外的其他内容。

于 2013-10-08T09:54:14.123 回答
2

我看到的唯一方法是 quellish 提到的。但是,您提到它存在于很多地方。

而不是重写所有当前代码,在你的pch中你可以做一些花哨的事情,比如

#import "UnitTestDateFormatter.h"
#define NSDateFormatter UnitTestDateFormatter

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

@implementation UnitTestDateFormatter

- (id) init
{
    self = [super init];

    if(self != nil)
    {
        [self setLocale:...];
    }

    return self;
}

@end

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

于 2013-10-11T08:44:18.473 回答