标签:
测试这个词很容易理解,那么什么是单元(Unit)呢?一个单元指的就是应用程序中可以测试的最小单元。一组源代码可以测试,一般要求有明确的输入与输出。因此一般来说源代码中明确的包含输入输出的每一个方法被认为一个测试的单元(一个case)。注意,这里的输出并不局限于方法的返回值对输入参数的改变,也包括方法在执行过程中改变的任何数据。
单元测试在程序里面可以理解一个模块一个方法,在每个可能存在的模块都进行测试,确保每个模块都没有问题,从而提高整体程序的质量。
单元测试的目的是将程序中所有的源代码,隔离成最小的可测试单元,以确保每个单元的正确性,如果每个单元都能保证正确,就能保证应用程序整体相当程度的正确性。另一方面测试脚本本身就是被测试代码的实际使用代码,这对于开发者理解被测试单元的使用是用帮助的。
测试是分黑盒测试和白盒测试(概念此处不在解释),单元测试其实就是一种白盒测试,开发者对现有已经实现的模块自己写对应测试脚本进行测试,这中间还包含测试用例的设计。相对来说还是由开发者自己来完成白盒测试,然后在交由测试团队进行黑盒测试,这样也更加有助于提升测试流程的完整性,最终提高产品的质量。
单元测试的内容:
- 单元测试的测试目的
- 模块接口测试
- 局部数据结构测试
- 路径测试
- 错误处理测试
- 边界测试
在现有的开发工作中,我们一般都会忽略掉单元测试的重要性,功能开发完成以后开发者拿到现有的测试用例,直接针对每条用例进行手工的测试,测试通过就进行提测,之后测试人员还是重复手工测试的流程、数据的mock、专项测试等,这样以来白盒测试的流程有时间份量会变的很低,开发人员不知道自己模块代码的覆盖路问题,更多的时间可能某些代码一直到到上线都从来没有跑过,以至于到了真实环境下会产生一些意想不到的问题,这样以来风险极高,整体来说单元测试还是至关重要的。
具体的怎么在Xcode上新建或者添加使用单元测试请阅读本文末尾的风之痕链接。
言归正传,本文主要讲 单元测试之NSNull 检测,在现实开发中,我们最烦的往往就是服务端返回的数据中隐藏着NSNull的数据,一般我们的做法是通过
[data isKindOfClass:[NSNull class]] 对数据先做一层判断然后为空的情况下付给 空字符串或者一些其他的初始变量。但是,业务数据层的代码本来就比较繁杂,还要我加上这个多余的判断来添堵?门都没有!那么我们的单元测试就派上用处了。
我们用一个带空数据的接口来走一遍流程。
数据大概是这样子的,其中data 下的 isLike字段的值是NSNull 状态
1.在test文件中新建一个test
- (void)testGetNoticeListWithExerciseType{ //此处换成你自己的接口 [NetManager getNoticeListWithExerciseType:@"" keyword:@"" pageSize:@"" pageNum:@"" whenSuccess:^(NSDictionary *responseDic) { //数据非空 XCTAssertNotNil(responseDic, @"返回出错"); //返回码为0的情况下是正确的 (这个你们的有可能不是) XCTAssertTrue([[responseDic objectForKey:@"code"] isEqualToNumber:@(0)],@"code 必须是@(0)"); //判断数据的所有层是否都为非空(可以返回一个免检字段的key数组,允许数组中的字段为空 ) [self judgeNilData:[responseDic objectForKey:@"data"] andKey:@"" finished:^NSArray *{ return @[@"isLike",@"like_count"]; }]; //判断数据的所有层是否都为非空(必须所有字段都未非空才能通过测试) //[self judgeNullData:[responseDic objectForKey:@"data"] andKey:nil exemptionKeys:nil]; NOTIFY //继续执行 } andFailed:^(NSString *errorDesc) { NOTIFY //继续执行 }]; //等待 WAIT }
2.核心代码(粘贴到该test文件下)
/** * 覆盖检测数据中是否含有NSNull 数据 * 日常中一般情况的下的闪退大多都是数据的空导致的,事先检测出是否包含空的数据能大大提升程序的稳定性 * * @param data 字典或者数组数据 (一般由json转化而来) * @param key data 的 key (多层数据情况下直接置nil即可) * @param keys 免检字段 (在这里 返回你运行为空的字段名称的key数组) */ - (void)judgeNullData:(nullable id)data andKey:(nullable NSString *)key exemptionKeys:( NSArray * (^)(void))keys{ //字典 if ([data isKindOfClass:[NSDictionary class]]) { for (id obj in ((NSDictionary *)data).allKeys) { //递归遍历字典 [self judgeNullData:[((NSDictionary *)data) objectForKey:obj] andKey:obj exemptionKeys:keys]; } } //数组 else if ([data isKindOfClass:[NSArray class]]) { for (id obj in data) { //递归遍历数组 [self judgeNullData:obj andKey:nil exemptionKeys:keys]; } } //除字典和数组外(进行非空判断) else{ //添加免检字段(允许array数组中的字段为NSNull) if (keys) { NSArray *array = keys(); if ([array containsObject:key]) { return; } } //断言检测字段非空 //检测nil XCTAssertNotNil(data); //这个断言不能判断 NSNull 只能判断nil //检测NSNull XCTAssertFalse([data isKindOfClass:[NSNull class]],@"字段为空"); //, @"字段为空" //打印输出空的字段 if ([data isKindOfClass:[NSNull class]]) { if (!(key == nil)) { NSLog(@"key:%@ 对应的值为NSNull",key); } } if (data == nil) { NSLog(@"数组为空"); } return; } }
3.如下图,点击左上角的开始测试
4.最后测试会报错,如下
以上简介部分文字摘自 文/风之痕_(简书作者)
标签:
原文地址:http://www.cnblogs.com/devyh/p/5443660.html