只有优秀的程序员才关心产品,只有优秀的程序员才在乎程序的性能,我们要具备性能测试和性能优化的能力,今天开始我开始给大家写一写介绍性能方面的文章,今天写单元测试.
单元测试简介如下:
- 单元测试是以代码测试代码
- 红灯/绿灯迭代开发
- 在日常开发中,数据大部分来自于网络,很难出现
所有的
边界数据!如果没有测试所有条件就上架
在运行时造成闪退! - 自己建立
测试用例(使用的例子数据,专门检查边界点)
- 单元测试不是靠 NSLog 来测试,NSLog 是程序员用眼睛看的笨办法。
提示:
- 不是所有的方法都需要测试
例如:私有方法不需要测试!只有暴露在 .h 中的方法需要测试!面向对象有一个原则:开闭原则! - 所有跟 UI 有关的都不需要测试,也不好测试!
MVVM,把小的业务逻辑
代码封装出来!变成可以测试的代码,让程序更加健壮! - 一般而言,代码的覆盖度大概在 50% ~ 70%
demo github地址 https://github.com/1271284056/Unit-test-Demo
希望大家多给点星星~~
-
创建项目时候勾选下面的Include Unit Tests
屏幕快照 2016-10-24 10.08.08.png -
如果创建项目时候没勾选这个选项,通过下图操作为项目添加单元测试.
- 在单元测试文件夹新建测试类
- 首先建立测试类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秒后如果执行到[expectation fulfill]这里表面单元测试成功
[self waitForExpectationsWithTimeout:10.0 handler:nil];
}
性能测试
以前我们测试一个函数执行时间,在开始时候定义起始时间
NSTimeInterval start = CACurrentMediaTime();
函数执行完毕后计算时间
NSLog(@"%f", CACurrentMediaTime() - start);
单元测试为我们提供一个- (void)testPerformanceExample {}函数,在这个函数的 [self measureBlock:^{}] 中写耗时操作, 相同的代码重复执行 10 次,统计计算时间,平均时间在控制台打印出来!
// 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.
// 将需要测量执行时间的代码放在此处!
for (int i = 0; i < 10000; i++) {
[Person personWithDict:@{@"name": @"zhang", @"age": @20}];
}
}];
}
网友评论