目前市场上有很多集成了各种功能的 SDK,开发者只需要调用 SDK 中提供的 API 就能实现一些原本实现起来比较复杂的功能,不需要关心怎样去跟 server 通信,也不用搭建自己的后端 server。我认为 SDK 这个东西秉承了 “让专业的人去做专业的事” 的精神,对开发者来说在某种程度上提供了很大的便利。
最近研究了下 iOS SDK 的接口测试,进行了总结。如有不对的地方,望不吝指正呀~
异步方法不像 require 方法那么容易上手,在文章最上面的那张图示中,当服务器会包返回给 app 时,被触发的回调就是异步函数,这个函数不会阻塞线程,而且什么时候被触发完全取决于服务器回包的时间间隔,所以当我们测试该类的方法时,需要满足这样的场景:当我们的回调函数被触发时,测试用例的代码才会结束执行。测试异步函数的方法也有很多,我这里采用的是给予 xctest 框架提供的 ‘expectationForNotification’ 和 ‘waitForExpectationsWithTimeout’ 函数以及 ios 的通知中心功能的一些函数来实现的,见如下代码:
- (void)testSendtextmessage{
NSString *text=@"文本消息";
//构造文本消息
NIMSession *session=[NIMSession session:_advanceTeamWithSendMessage type: NIMSessionTypeTeam];
NIMMessage *message=[[NIMMessage alloc] init];
message.text=text;
//调用发送消息的API
[_chatmanager sendMessage:message toSession:session error:nil];
//监听ios通知中心是否有内容为'SendMassageSuccess'通知消息
[self expectationForNotification:@"SendMassageSuccess" object:nil handler:nil];
//监听的行为最多持续60s,60s之内收到了该条通知消息,测试执行直接结束。60s之内没有受到则说明有问题
[self waitForExpectationsWithTimeout:60 handler:nil];
}
//异步回调函数
- (void)sendMessage:(NIMMessage *)message didCompleteWithError:(NSError *)error
{
//此处可以添加一些对服务器回包数据的判断代码
//向ios通知中心发送内容为'SendMassageSuccess'通知消息
[[NSNotificationCenter defaultCenter] postNotificationName:@"SendMassageSuccess" object:nil];
}
如代码中的注释所解释的那样,我们在异步函数中做了一件事情,就是向 ios 通知中心的发送消息,而在测试代码的 case 中去针对这个通知消息做异步等待,并设置一个最大的超时时间,以此来实现判断异步函数是否被正确的触发以及服务器数据回包是否正确。
作为一个 tester,我们大量的工作就是测试各种不同的场景结果是否符合预期,一套参数组合就是一个测试用例。转换到 SDK 的接口测试,我们可以用一种比较巧妙的办法,避免一种参数组合写一个测试 case,而是通过循环与 random 的结合,达到同样的效果。
举个例子我在测试中,有一个 “创建高级群” 的接口,这个接口有 2 个参数(在此只拿 2 个参数为例,实际情况下更多):参数 1-申请入群的权限(枚举值 0-直接申请即可加入,1-申请后需管理员同意才可加入),参数 2-修改群资料的权限(枚举值 0-仅群主可修改,1-群主和管理员可修改,2-所有人均可修改)。这样这个接口就有 2X3=6 中参数的组合情况,最直接最暴力的方法是写 6 个结构类似的测试 case,保障这个接口是 OK 的,但是这样会造成代码很多很冗余,正如题目所述,可以利用 random 这个特性来搞些事情。如下图所示:
- (void)testCreateAdvancedTeam
{
NSString *userId = [[[NIMSDK sharedSDK] loginManager] currentAccount];
NSArray *users = @[userId];
NSMutableArray *teamIds = [NSMutableArray array];
//利用循环+random构造case
for (NSInteger index = 0; index < 6; index++)
{
//构建群时所需要的参数
NIMCreateTeamOption *option = [[NIMCreateTeamOption alloc] init];
//申请入群的权限的参数在0和1之间随机产生
option.joinMode = arc4random() % 2;
//修改群资料权限的参数在0、1、2之间随机产生
option.updateInfoMode = arc4random() % 3;
//调用创见高级群的API
[[[NIMSDK sharedSDK] teamManager] createTeam:option
users:users
completion:^(NSError *error, NSString *teamId) {
//一些对返回结果的判断代码
}];
}
}
上述代码就是通过做循环+每次随机产生随机参数的模式来减少代码量,从严格意义来讲并不是安全严谨的,但是若参数组合有 12 种情况,其中一个参数每次都没被随机到的概率为 1/12,而且我们的测试工程代码并不是仅仅跑一次,可能会跑很多次,这样的话某个参数不被覆盖的的概率会很小很小,数学的力量!!
在编写测试用例的时候,有些场景是多次重复使用的,比如发送一个图片消息等等,我们可以把构造一条图片消息封装成一个公共类,而不要傻傻的每用一次就代码编写一次生成图片的代码。随着测试用例的丰富,你的测试工程中应该有各种各样的公共类,方便你实现各种各样的测试场景。所以,随着你的测试用例越来越多,你的测试公共类也应该越来越丰富。
当测试代码有一定数量的时候,这时候你就得考虑一个问题,我写的测试代码到底 “好” 还是 “不好”。这里不能简单地用测试用例的个数或者测试代码的数量来衡量,因为很有可能你的测试用例有大量的重复测试,比较科学的方法是统计测试工程的代码覆盖率。关于如何统计代码覆盖率,苹果的官方文档(后文参考文献会给出)中专门有一个章节'code coverage'说明,这里就不详细讲了,各位看官自己去了解下吧:D。