爱上iOS单元测试系列之爱上她就要先了解她:单元测试入门

前言

对于单元测试一开始我是拒绝的。单元测试是一个什么东东,因为我喜欢做iOS开发是因为喜欢写APP的啊,一切和这一目标不相干的东西我没兴趣啊,所以从事iOS开发几年都没去深入学习过单元测试(主要是之前单位没这要求)。看到我的优点木有:目标性很强,嗯,记住我的优点,请忽略我拒绝学习边缘知识的缺点。但是最近被总监要求负责单元测试的探索和落地,我义(勉)不(为)容(其)辞(难)地扛起了夺取桥头堡的重任。随着对这个姑娘的不断的了解和接触,我发现自己逐渐爱上了她,她有着独立知性的气质,有着完美丰满的身材,有着自我成长过程中不断丰富而且深刻的阅历。她是如此地完美的,让我神魂颠倒,夜不能寐,我想为她写诗(可惜没有文学细胞),我想为她写歌(可惜没有艺术细胞),我想为她写书立传(可惜没有写作天赋)。讲真:有木有有眼无珠的出版社愿意邀约?我真的想写一本单元测试的书,我先写几篇关于的她的文章,您看看我有没有出这本书的潜力。

我先来给你介绍下这位姑娘。

单元测试的魅力

每个男人都有过自己喜欢的女孩,可能还有多个,他们可能有你喜欢的共同特质,比如有人喜欢个子高的,有人喜欢小巧的,也有喜欢丰满的,有人喜欢可爱的,有人喜欢野蛮的,也有喜欢……此处省略各种奇葩极端偏好,毕竟人各有所好嘛。但身为一名合格的程序员,你理想的中的女神,如果她有如下优点,一定会让你爱的无法自拔:

1.她能让你更自信。帮助你编写高质量代码、减少bug。
如果大家分析一下我们bug原因的构成,我想有会有一部分bug的原因是开发人员在编写工作代码的时候没有考虑到某些case或者边际条件。造成这种问题的原因很多,其中很重要的一个原因是我们对工作代码所要完成的功能思考不足,而编写单元测试,特别是先写单元测试再写工作代码就可以帮助开发人员思考编写的代码到底要实现哪些功能。例如实现一个简单的用户注册功能的业务类方法,用单元测试再写工作代码的方式来工作的话开发人员就会先考虑各种场景相关,例如正常注册、用户名重复、没有满足必要的填写内容......等等,之后就会编写相关的测试用例。编写单元测试代码的过程就是促使开发人员思考工作代码实现内容和逻辑的过程,之后实现工作代码的时候,开发人员思路会更清晰,实现代码的质量也会有相应的提升。
2.她能提提升你的战斗力。帮助你提升代码的反馈速度,减少重复工作,提高开发效率。 
开发人员实现某个功能或者修补了某个bug,如果有相应的单元测试支持的话,开发人员可以马上通过运行单元测试来验证之前完成的代码是否正确,而不需要反复通过编译运行simulator、等待应用启动、通过输入数据等繁琐的步骤来验证所完成的功能。用单元测试代码来验证代码和通过发布应用以人工的方式来验证代码这两者的效率差很多,所以单元测试其实还能节约人力成本。
3.她的存在让你轻松愉快。保证你最后的代码修改不会破坏之前代码的功能。 
项目越做越大,代码越来越多,特别涉及到一些公用接口之类的代码或是底层的基础库,谁也不敢保证这次修改的代码不会破坏之前的功能,所以与此相关的需求会被搁置或推迟,由于不敢改进代码,代码也变得越来越难以维护,质量也越来越差。而单元测试就是解决这种问题的很好方法(不敢说最好的)。由于代码的历史功能都有相应的单元测试保证,修改了某些代码以后,通过运行相关的单元测试就可以验证出新调整的功能是否有影响到之前的功能。当然要实现到这种程度需要很大的付出,不但要能够达到比较高的测试覆盖率,而且单元测试代码的编写质量也要有保证。
4.她能为你排忧解难,永远做你的依靠。让你的代码维护更容易。 
由于给代码写很多单元测试,相当于给代码加上了规格说明书,开发人员通过读单元测试代码也能够帮助开发人员理解现有代码。很有Open Source的项目(如,AFNetworking, FMDB,喵神的VVDoucment等)都有相当量的单元测试代码,通过读这些测试代码会有助于理解生产源代码。
5.她甘心做你坚强的后盾,在你卖命打拼时无后顾之忧。她有助于改进代码质量和设计。 
除了那些大拿们编写的代码,我相信很多易于维护、设计良好的代码都是通过不断的重构才得到的。虽然说单元测试本身不能直接改进生产代码的质量,但它为生产代码提供了“安全网”,让开发人员可以勇敢地改进代码,从而让代码的clean和beautiful不再是梦想。

我这么辛苦把它吹的这么有魅力,要是你作为程序员还不想见见她,wakao,我猜你不正常,有必要做个自身能力检查。如果你跟我一样是一个正常人,下面我就暂不收费,带你远远的瞧上一瞧这位美女,看看她到底长什么样子。

iOS单元测试初探

维基百科上的对她解释:“在计算机编程中,单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。”。

通常来说,程序员每修改一次代码就会修改某个单元,那我们就可以对这个单元做修改的验证(单元测试),在编写程序的过程中前后很可能要进行多次单元测试,以证实程序达到软件规格书(产品需求)要求的工作目标,而且没有程序错误。虽然单元测试不是什么必须的,但也不坏,这牵涉到项目管理的政策决定(说白了,你没有她也能活,但是只能自己左手写代码,右手……当然也是写代码,作为程序员怎么可以一只手敲代码呢)。

1.了解XCode中的单元测试

在XCode7中新建一个工程的时候,会默认带一个用于单元测试的target,其名字为工程名加Test后缀,并且文件名也以Test结尾。你会发现已经有了一个默认的测试用例。

创建项目后,默认会给我们创建一个和bundle名称+Tests.m的测试类,它包含的默认代码含义如下:

  - (void)setUp {
       [super setUp];
       // Put setup code here. This method is called before the  invo cation of each test method in the class.
      //初始化的代码,在测试方法调用之前调用
}

- (void)tearDown {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
       // 释放测试用例的资源代码,这个方法会每个测试用例执行后调用
       [super tearDown];
}

- (void)testExample {
           // This is an example of a functional test case.
           // Use XCTAssert and related functions to verify your tests produce the correct results.
           // 测试用例的例子,注意测试用例一定要test开头

}

- (void)testPerformanceExample {
         // This is an example of a performance test case.
         // 测试性能例子,有Instrument调试工具之后,其实这个没毛用。
         [self measureBlock:^{
         // Put the code you want to measure the time of here.
         // 需要测试性能的代码
          }];
}

2.写一个简单的测试用例 
在testExample方法中输入

- (void)testExample {
    // This is an example of a functional test case.
    // Use XCTAssert and related functions to verify your tests produce the correct results.
    NSLog(@"开始爱上单元测试的第一个单元测试测试");
    NSString *test = @"这是我的第一个单元测试";
    XCTAssertTrue([test isEqualToString:@"初来乍到,就想测试成功,没门"]);
}

然后按快捷键Command + U进行单元测试,这个快捷键是全部测试。可以看到如下结果界面:

由于我们使用了断言XCTAssetTrue,它用来比较一个表达式是否为真,显然这个表达式是返回false的,所以这个测试用例肯定通过不了嘛。

我们也可以点击播放按钮,测试某个测试用例。

3.XCTest常见的断言

XCTFail(format…) 生成一个失败的测试;

XCTAssertNil(a1, format...)为空判断,a1为空时通过,反之不通过;

XCTAssertNotNil(a1, format…)不为空判断,a1不为空时通过,反之不通过;

XCTAssert(expression, format...)当expression求值为TRUE时通过;

XCTAssertTrue(expression, format...)当expression求值为TRUE时通过;

XCTAssertFalse(expression, format...)当expression求值为False时通过;

XCTAssertEqualObjects(a1, a2, format...)判断相等,[a1 isEqual:a2]值为TRUE时通过,其中一个不为空时,不通过;

XCTAssertNotEqualObjects(a1, a2, format...)判断不等,[a1 isEqual:a2]值为False时通过;

XCTAssertEqual(a1, a2, format...)判断相等(当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以);

XCTAssertNotEqual(a1, a2, format...)判断不等(当a1和a2是 C语言标量、结构体或联合体时使用);

XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)判断相等,(double或float类型)提供一个误差范围,当在误差范围(+/-accuracy)以内相等时通过测试;

XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...) 判断不等,(double或float类型)提供一个误差范围,当在误差范围以内不等时通过测试;

XCTAssertThrows(expression, format...)异常测试,当expression发生异常时通过;反之不通过;(很变态) XCTAssertThrowsSpecific(expression, specificException, format...) 异常测试,当expression发生specificException异常时通过;反之发生其他异常或不发生异常均不通过;

XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)异常测试,当expression发生具体异常、具体异常名称的异常时通过测试,反之不通过;

XCTAssertNoThrow(expression, format…)异常测试,当expression没有发生异常时通过测试;

XCTAssertNoThrowSpecific(expression, specificException, format...)异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过;

XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过

特别注意下XCTAssertEqualObjects和XCTAssertEqual。
XCTAssertEqualObjects(a1, a2, format...)的判断条件是[a1 isEqual:a2]是否返回一个YES。XCTAssertEqual(a1, a2, format...)的判断条件是a1 == a2是否返回一个YES。对于后者,如果a1和a2都是基本数据类型变量,那么只有a1 == a2才会返回YES。

结尾

点到为止,入门就是入门,让你稍微有个了解。就像给你介绍一个美女,我会给她带朦胧的面纱,等你开个好价钱(点个赞)之后我才会一步一步揭开它的面纱,(bie四声)着急,好东西就要一点点的看看才有味道嘛。后面我会陆续推出单元测试进阶,单元测试实战,单元测试中的各种技巧等系列的文章。

参考文章:

《Using Unit Tests》

《iOS开发:XCTest单元测试(附上一个单例的测试代码》

时间: 2024-10-08 10:28:02

爱上iOS单元测试系列之爱上她就要先了解她:单元测试入门的相关文章

从此爱上iOS Autolayout

转:从此爱上iOS Autolayout 这篇不是autolayout教程,只是autolayout动员文章和经验之谈,在本文第五节友情链接和推荐中,我将附上足够大家熟练使用autolayout的教程.这篇文章两个月前就想写下来,但因为一直工作较多,没有时间来完成.今天终于狠下心,丢下代码不写,来完成他吧! 一.别和我提Autolayout,我想死!! 从iOS6/xcode4开始,苹果开始提供了autolayout——一种对不同屏幕尺寸有更好兼容的自动布局机制,但我相信大多数人在刚接触auto

iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

iOS开发系列--音频播放.录音.视频播放.拍照.视频录制 转载:http://www.cnblogs.com/kenshincui/p/4186022.html#avFoundationCamera --iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操作都提供了多套API.在今天的文章中将会对这些内容进行一一介绍: 音频 音

iOS开发系列--数据存取

概览 在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库.例如前面IOS开发系列—Objective-C之Foundation框架的文章中提到归档.plist文件存储,包括偏好设置其本质都是存储为文件,只是说归档或者plist文件存储可以选择保存到沙盒中,而偏好设置系统已经规定只能保存到沙盒的Library/Preferences目录.当然,文件存储并不作为本文的重点内容.本文重点还是说数据库存储,做过数据库开发的朋友应该知道,可以通过SQL直接访问数据库,也可以

iOS开发系列--网络开发

iOS开发系列--网络开发 2014-10-22 08:34 by KenshinCui, 50097 阅读, 53 评论, 收藏,  编辑 概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力的.今天就会给大家介绍这部分内容: Web请求和响应 使用代理方法 简化请求方法 图片缓存 扩展--文件分段下载 扩展--文件上传 NSURLSession

IOS开发系列--C语言之构造类型

概述 在第一节中我们就提到C语言的构造类型,分为:数组.结构体.枚举.共用体,当然前面数组的内容已经说了很多了,这一节将会重点说一下其他三种类型. 结构体 枚举 共用体 结构体 数组中存储的是一系列相同的数据类型,那么如果想让一个变量存储不同的数据类型就要使用结构体,结构体定义类似于C++.C#.Java等高级语言中类的定义,但事实上它们又有着很大的区别.结构体是一种类型,并非一个变量,只是这种类型可以由其他C语言基本类型共同组成. // // main.c // ConstructedType

iOS开发系列--网络开发网络联网程序

概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力的.今天就会给大家介绍这部分内容: Web请求和响应 使用代理方法 简化请求方法 图片缓存 扩展--文件分段下载 扩展--文件上传 NSURLSession 数据请求 文件上传 文件下载 会话 UIWebView 浏览器实现 UIWebView与页面交互 网络状态 目 录 Web请求和响应 使用代理

iOS开发系列--让你的应用“动”起来

--iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建基础动画.关键帧动画.动画组.转场动画,如何通过UIView的装饰方法对这些动画操作进行简化等.在今天的文章里您可以看到动画操作在iOS中是如何简单和高效,很多原来想做但是苦于没有思路的动画在iOS中将变得越发简单: CALayer CALayer简介 CALayer常用属性 CALayer绘图 C

iOS开发系列文章(持续更新……)

iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大家交流,新建一个iOS技术交流群,欢迎大家加入:64555322 C语言 IOS开发系列--C语言之基础知识 IOS开发系列--C语言之数组和字符串 IOS开发系列--C语言之指针 IOS开发系列--C语言之预处理 IOS开发系列--C语言之存储方式和作用域 IOS开发系列--C语言之构造类型 Ob

iOS开发系列--通知与消息机制

概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地通知:另一类是推送通知,也叫远程通知.两种通知在iOS中的表现一致,可以通过横幅或者弹出提醒两种形式告诉用户,并且点击通知可以会打开应用程序,但是实现原理却完全不同.今天就和大家一块去看一下如何在iOS中实现这两种机制,并且在文章后面会补充通知中心的内容避免初学者对两种概念的混淆. 本地通知 推送通