只有優(yōu)秀的程序員才關心產品,只有優(yōu)秀的程序員才在乎程序的性能,我們要具備性能測試和性能優(yōu)化的能力,今天開始我開始給大家寫一寫介紹性能方面的文章,今天寫單元測試.
單元測試簡介如下:
- 單元測試是以代碼測試代碼
- 紅燈/綠燈迭代開發(fā)
- 在日常開發(fā)中,數據大部分來自于網絡,很難出現
所有的
邊界數據!如果沒有測試所有條件就上架
在運行時造成閃退! - 自己建立
測試用例(使用的例子數據卜壕,專門檢查邊界點)
- 單元測試不是靠 NSLog 來測試,NSLog 是程序員用眼睛看的笨辦法。
提示:
- 不是所有的方法都需要測試
例如:私有方法不需要測試糊昙!只有暴露在 .h 中的方法需要測試!面向對象有一個原則:開閉原則谢谦! - 所有跟 UI 有關的都不需要測試释牺,也不好測試!
MVVM回挽,把小的業(yè)務邏輯
代碼封裝出來没咙!變成可以測試的代碼,讓程序更加健壯千劈! - 一般而言祭刚,代碼的覆蓋度大概在 50% ~ 70%
demo github地址 https://github.com/1271284056/Unit-test-Demo
希望大家多給點星星~~
-
創(chuàng)建項目時候勾選下面的Include Unit Tests
屏幕快照 2016-10-24 10.08.08.png 如果創(chuàng)建項目時候沒勾選這個選項,通過下圖操作為項目添加單元測試.
- 在單元測試文件夾新建測試類
- 首先建立測試類Person類,建立它的初始化方法,以及異步方法.
Preson.h
import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic) NSInteger age;
- (instancetype)personWithDict:(NSDictionary *)dict;
/// 異步加載個人記錄 - (void)loadPersonAsync:(void (^)(Person *person))completion;
@end
Preson.m
import "Person.h"
@implementation Person
- (instancetype)personWithDict:(NSDictionary *)dict {
Person *obj = [[self alloc] init];
[obj setValuesForKeysWithDictionary:dict];
if (obj.age <= 0 || obj.age >= 130) {
obj.age = 0;
}
return obj;
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {}
- (void)loadPersonAsync:(void (^)(Person *))completion {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[NSThread sleepForTimeInterval:1.0];
Person *person = [Person personWithDict:@{@"name": @"z", @"age": @5}];
dispatch_async(dispatch_get_main_queue(), ^{
if (completion != nil) {
completion(person);
}
});
});
}
單元測試方法名都以test開頭,寫完后左邊會有一個菱形,點擊菱形,運行變成綠色就是成功,紅色表示失敗.
- (void)testNewPerson {
[self checkPersonWithDict:@{@"name": @"zhang", @"age": @20}];
[self checkPersonWithDict:@{@"name": @"zhang"}];
[self checkPersonWithDict:@{}];
[self checkPersonWithDict:@{@"name": @"zhang", @"age": @20, @"title": @"boss"}];
[self checkPersonWithDict:@{@"name": @"zhang", @"age": @200, @"title": @"boss"}];
[self checkPersonWithDict:@{@"name": @"zhang", @"age": @-1, @"title": @"boss"}];
// 到目前為止 Person 的 工廠方法測試完成!
}
/// 根據字典檢查新建的 Person 信息
- (void)checkPersonWithDict:(NSDictionary *)dict {
Person *person = [Person personWithDict:dict];
NSLog(@"%@", person);
// 獲取字典信息
NSString *name = dict[@"name"];
NSInteger age = [dict[@"age"] integerValue];
// 1. 檢查名稱,使用斷言
來測試的墙牌,提前預判條件必須滿足涡驮!
XCTAssert([name isEqualToString:person.name] || person.name == nil, @"姓名不一致");
// 2. 檢查年齡
if (person.age > 0 && person.age < 130) {
XCTAssert(age == person.age, @"年齡不正確");
} else {
XCTAssert(person.age == 0, @"年齡超限");
}
}
異步單元測試
/**
蘋果的單元測試是串行的
setUp
testXXX1
testXXX2
testXXX3
tearDown
中間不會等待異步的回調完成
*/
/// 測試異步加載 Person
- (void)testLoadPersonAsync {
// Xcode 6.0 開始解決Expectation
預期
XCTestExpectation *expectation = [self expectationWithDescription:@"異步加載 Person"];
[Person loadPersonAsync:^(Person *person) {
NSLog(@"%@", person.name);
// 標注預期達成
[expectation fulfill];
}];
// 等待 10s 期望預期達成 10秒后如果執(zhí)行到[expectation fulfill]這里表面單元測試成功
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
性能測試
以前我們測試一個函數執(zhí)行時間,在開始時候定義起始時間
NSTimeInterval start = CACurrentMediaTime();
函數執(zhí)行完畢后計算時間
NSLog(@"%f", CACurrentMediaTime() - start);
單元測試為我們提供一個- (void)testPerformanceExample {}函數,在這個函數的 [self measureBlock:^{}] 中寫耗時操作, 相同的代碼重復執(zhí)行 10 次,統(tǒng)計計算時間喜滨,平均時間在控制臺打印出來捉捅!
// Performance 性能!
/*
性能測試代碼一旦寫好鸿市,可以隨時測試锯梁!
*/
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
// 將需要測量執(zhí)行時間的代碼放在此處即碗!
for (int i = 0; i < 10000; i++) {
[Person personWithDict:@{@"name": @"zhang", @"age": @20}];
}
}];
}