iOSユニットのテストはどう書きますか?
6218 ワード
ユニットテストとは?
プログラムモジュール(ソフトウェア設計の最小単位)に対して正確性検査のテスト作業を行う.プログラムユニットは、アプリケーションの最小テスト可能な部品です.オブジェクト向けプログラミングの場合、最小ユニットはiOSが独自のテストフレームワークOCUnitとUItestsを統合した方法です.
ユニットテストはなぜですか?
ユニットテストを実行するのは、このコードの動作が私たちの期待と一致していることを証明するためです.例えば、いくつかの機能が正常かどうか、インタフェースが正常かどうか、特にいくつかの大きなプロジェクトで、プログラムが誤って変更されたり、新しい問題を引き起こしたりすることを防止します.ユニットテストにはいくつかのメリットがあります.
ユニットテストはどう書きますか?
私はユニットテストを書いたばかりで、ネット上にたくさんの文章を見たが、まだ手がつけられない.本文はいくつかの点をまとめ,いくつかの例を抜粋した.
ユニットテストコードを作成するときに、テスト方法で使用される可能性のある外部データを理解してから、これらの外部データを上記のように一度に設定してから、方法を実行します.これにより、外部データのすべての状況が正しくテストされるようになります.
抜粋したいくつかの例
**例1**論理テストの操作手順の前後で、対応するデータが変更されたはずです.そうすれば、テストを容易にすることができます.
@interface LXDTestsModel : NSObject
@property (nonatomic, readonly, copy) NSString * name;
@property (nonatomic, readonly, strong) NSNumber * age;
@property (nonatomic, readonly, assign) NSUInteger flags;
+ (instancetype)modelWithName: (NSString *)name age: (NSNumber *)age flags: (NSUInteger)flags;
- (instancetype)initWithDictionary: (NSDictionary *)dict;
- (NSDictionary *)modelToDictionary;
@end
テスト例では、モデルとjson間の変換が正しいかどうかをテストするためのtestModelConvertメソッドを定義しました.
- (void)testModelConvert
{
NSString * json = @"{\"name\":\"SindriLin\",\"age\":22,\"flags\":987654321}";
NSMutableDictionary * dict = [[NSJSONSerialization JSONObjectWithData: [json dataUsingEncoding: NSUTF8StringEncoding] options: kNilOptions error: nil] mutableCopy];
LXDTestsModel * model = [[LXDTestsModel alloc] initWithDictionary: dict];
XCTAssertNotNil(model);
XCTAssertTrue([model.name isEqualToString: @"SindriLin"]);
XCTAssertTrue([model.age isEqual: @(22)]);
XCTAssertEqual(model.flags, 987654321);
XCTAssertTrue([model isKindOfClass: [LXDTestsModel class]]);
model = [LXDTestsModel modelWithName: @"Tessie" age: dict[@"age"] flags: 562525];
XCTAssertNotNil(model);
XCTAssertTrue([model.name isEqualToString: @"Tessie"]);
XCTAssertTrue([model.age isEqual: dict[@"age"]]);
XCTAssertEqual(model.flags, 562525);
NSDictionary * modelJSON = [model modelToDictionary];
XCTAssertTrue([modelJSON isEqual: dict] == NO);
dict[@"name"] = @"Tessie";
dict[@"flags"] = @(562525);
XCTAssertTrue([modelJSON isEqual: dict]);
}
**例2**ユニットテストはメインスレッドで行われるため、非同期操作のテストは実行が完了する前に終了することが多い.解決方法は二つある
//waitForExpectationsWithTimeout , 。
#define WAIT do {
[self expectationForNotification:@"RSBaseTest" object:nil handler:nil];
[self waitForExpectationsWithTimeout:30 handler:nil];
} while (0)
#define NOTIFY [[NSNotificationCenter defaultCenter]postNotificationName:@"RSBaseTest" object:nil]
-(void)testRequest{
// 1.
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
mgr.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html",nil];
// 2. GET
[mgr GET:@"http://www.weather.com.cn/adat/sk/101110101.html" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"responseObject:%@",responseObject);
XCTAssertNotNil(responseObject, @" ");
NOTIFY //
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"error:%@",error);
XCTAssertNil(error, @" ");
NOTIFY //
}];
WAIT //
}
- (void)downloadImageURLWithString:(NSString *)URLString
{ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSURL *url = [NSURL URLWithString:URLString];
__unused Photo *photo = [[Photo alloc] initwithURL:url
withCompletionBlock:^(UIImage *image, NSError *error) {
if (error) {
XCTFail(@"%@ failed. %@", URLString, error);
}
dispatch_semaphore_signal(semaphore);
}];
dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, kDefaultTimeoutLengthInNanoSeconds);
if (dispatch_semaphore_wait(semaphore, timeoutTime)) {
XCTFail(@"%@ timed out", URLString);
}
}
**オープンソースプロジェクト**でよく使われる第三者フレームワーク、例えばYYModel、AFNetworking、Alamofireなどの優れたフレームワークの中にも、フレームワーク自体に対して作成されたユニットテストがあり、これらのユニットテストを模倣することを学ぶことも、自分を迅速に向上させる手段です.