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

次のような内容で、私のアサーションで 2 つ以上の言語を取り上げたいと思います。

[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か? シミュレーター全体でロケールを設定する必要はありません。テストのパラメーターにすることができます。ロケールに依存するほとんどの 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: メソッドはここに文書化されており、ロケール以外のすべてについてかなり明示的です。したがって、同じ手順を実行できますが、上記の手順を使用してロケールをシステムの現在のロケール以外に設定します。

于 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 に答える