iOS开发:XCTest单元测试(附上一个单例的测试代码)
测试驱动开发并不是一个很新鲜的概念了。在我最开始学习程序编写时,最喜欢干的事情就是编写一段代码,然后运行观察结果是否正确。我所学习第一门语言是c语言,用的最多的是在算法设计上,那时候最常做的事情就是编写了一段代码,如何编译运行,查看结果是否正确,很多时候,还得自己想很多特殊的(比如说零值,边界值)测试数据来检测所写代码、算法是否正确。那个时候,感觉还好,比较输出只是只是控制台的一个简单的数字或者字符。在学习iOS开发中,很多时候也是要测试的,这种输出是必须在点击一系列按钮之后才能在屏幕上显示出来的东西。测试的时候,往往是用模拟器一次一次的从头开始启动app,然后定位到自己所在模块的程序,做一系列的点击操作,然后查看结果是否符合自己预期。
这种行为无疑是对美好生命和绚丽青春的巨大浪费。于是有很多资深工程师们发现,我们是可以在代码中构造一个类似的场景,然后在代码中调用我们之前想要检查的代码,并将运行结果和设想结果在程序中进行比较,如果一致,则说明我们的代码没有问题。比如说下面的代码:
1 2 3 4 5 6 7 8 9 10 |
int a
= 3, b = 4;
int c
= a + b;
if (c
== a + b){
//结果正确
}
else {
//结果错误
}
|
当测试足够全面、具有代表性的时候,我们就可以肯定这个代码是没有问题的,至少,问题不是出自这块代码。我们做出某些条件和假设,并以其为条件使用到被测试中的代码去,比较预期结果与运行结果是否相等,这就是软件测试中的基本方法。
首先什么是单元测试?维基百科中的解释是:
在计算机编程中,单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
通常来说,程序员每修改一次程序就会进行最少一次单元测试,在编写程序的过程中前后很可能要进行多次单元测试,以证实程序达到软件规格书(en:Specification)要求的工作目标,没有程序错误;虽然单元测试不是什么必须的,但也不坏,这牵涉到项目管理的政策决定。
在XCode中使用XCTest
在XCode7中新建一个工程的时候,会默认带一个用于单元测试的target,其名字为工程名加Test后缀,并且文件名也以Test结尾。你会发现已经有了一个默认的测试用例
注意到画勾的地方,Include Unit Test就是包含单元测试的意思。打开工厂目录,你会发现有如下文件:
其中,ZYMusicPlayerTests文件夹目录下的文件就是我们的单元测试文件。
新建一个工程的时候,会默认带一个用于单元测试的target,其名字为工程名加Tests后缀,并且文件名也以Test结尾。你会发现已经有了一个默认的测试用例,其中有四个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#import
<XCTest/XCTest.h>
@interface ZYMusicPlayerTests
: XCTestCase
@end
@implementation ZYMusicPlayerTests
-
( void )setUp
{
[ super setUp];
//
Put setup code here. This method is called before the invocation 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.
//
XCTFail(@"no implementation for app",__PRETTY_FUNCTION__);
}
-
( void )testPerformanceExample
{
//
This is an example of a performance test case.
[ self measureBlock:^{
}];
}
@end
|
四个方法分别是:setUp, tearDown, testExample, testPerformanceExample。其中testExample方法左侧有一个播放按钮,点击它就会对这个方法进行测试,而在整个文件的@implemenation那行也有个同样的按钮,点击后会对当前测试用例的所有方法进行测试,也可通过Command+U快捷键来触发。这个测试用例类没有头文件,因为测试用例不需要给外部暴漏接口。按照苹果官方的文档,建立一个测试用例的过程应该是这样的:
- 建立一个
XCTestCase
的子类 - 实现测试方法
- 选择性的定义一些实例变量来存储fixture的状态
- 通过重写
setUp
方法选择性的实例化fixture - 通过重写
tearDown
方法来在测试后清除
测试方法没有参数和返回值,用test作为前缀,比如:- (void)testPlayingMusic
会自动被XCTest
架构识别为测试用例,每个XCTestCase
的子类中的defaultTestSuite
都是一个XCTestSuite
,它包含了这些测试用例。
测试方法的实现经常包含断言,必须通过验证才能通过测试,举个例子:
下面是使用时的所有断言测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
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)以内相等时通过测试;
|