原创blog,转载请注明出处

blog.csdn.net/hello_hwc

欢迎关注我的iOS-SDK具体解释专栏

http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html


前言:測试是一个好的App必不可少的部分。每个App都是由一个个小的功能组合到一起的。

而这些小的功能又是由一个个函数或者说算法组合到一起的。单元測试就是对这些小的功能或者函数进行測试,良好的单元測试会让代码的健壮性提高非常多。XCTest就是XCode为我们提供的一个框架,它提供了各个层次的測试。


XCTestCase

每个XCode创建iOS的project中都有一个叫做”project名Tests”的分组,这个分组里就是XCTestCase的子类。XCTest中的測试类都是继承自XCTestCase。

比如新建一个project,命名为Demo。就能看到如图



看一下这个自己主动创建的文件中都包括了哪些内容

#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h> @interface DemoTests : XCTestCase @end @implementation DemoTests - (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.
XCTAssert(YES, @"Pass");
} - (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
} @end

測试用例的命名

XCTest中全部的測试用例的命名都是以test开头的。比如上文中的

- (void)testExample {
// This is an example of a functional test case.
XCTAssert(YES, @"Pass");
}

setUp和tearDown

Setup是在全部測试用例执行之前执行的函数,在这个測试用例里进行一些通用的初始化工作

tearDown是在全部的測试用例都执行完毕后执行的


XCode的測试用例导航

測试用例的导航如图。在測试用例的导航里,我们能够执行一组測试用例,也能够执行一个单独的測试用例

能够鼠标右键来新建一组測试用例。

也能够为測试用例加入失败断点来方便我们调试


普通方法測试

比如,新建一个类命名为Model,他有这种方法用来生成10以内的随机数。

-(NSInteger)randomLessThanTen{
return arc4random()%10;
}

于是。測试方法为

-(void)testModelFunc_randomLessThanTen{
Model * model = [[Model alloc] init];
NSInteger num = [model randomLessThanTen];
XCTAssert(num<10,@"num should less than 10");
}

我们点击如图的左边图标单独执行这个測试用例,当然也能够在上文我提到的导航栏里单独执行。



然后会看到输出表示这个測试用例通过

Test Suite 'Selected tests' started at 2015-06-28 05:24:56 +0000
Test Suite 'DemoTests.xctest' started at 2015-06-28 05:24:56 +0000
Test Suite 'DemoTests' started at 2015-06-28 05:24:56 +0000
Test Case '-[DemoTests testModelFunc_randomLessThanTen]' started.
Test Case '-[DemoTests testModelFunc_randomLessThanTen]' passed (0.000 seconds).
Test Suite 'DemoTests' passed at 2015-06-28 05:24:56 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:24:56 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.001) seconds
Test Suite 'Selected tests' passed at 2015-06-28 05:24:56 +0000.

经常使用断言

怎样推断一个測试用例成功或者失败呢?XCTest使用断言来实现。

最主要的断言

表示假设expression满足。则測试通过,否则相应format的错误。

XCTAssert(expression, format...)

另一个用来直接Fail的断言

XCTFail(format...)

其它一些经常使用的断言:

XCTAssertTrue(expression, format...)
XCTAssertFalse(expression, format...)
XCTAssertEqual(expression1, expression2, format...)
XCTAssertNotEqual(expression1, expression2, format...)
XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)
XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)
XCTAssertNil(expression, format...)
XCTAssertNotNil(expression, format...)

性能測试

所谓性能測试,主要就是评估一段代码的执行时间,XCTest的性能的測试利用例如以下格式

- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}

比如。我要评估一段代码。这段代码的功能是把一张图片缩小到指定的大小。

这段代码例如以下,这段代码我放在UIImage的类别里。

+ (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext(); return newImage;
}

然后測试用比如图,主要推断resize后是否为nil。而且尺寸是否对。

- (void)testPerformanceExample {
UIImage * image = [UIImage imageNamed:@"icon.png"];
[self measureBlock:^{
UIImage * resizedImage = [UIImage imageWithImage:image scaledToSize:CGSizeMake(100, 100)];
XCTAssertNotNil(resizedImage,@"resized image should not be nil");
CGFloat resizedWidth = resizedImage.size.width;
CGFloat resizedHeight = resizedImage.size.height;
XCTAssert(resizedHeight == 100 && resizedWidth == 100,@"Size is not right");
}];
}

输出

Test Suite 'Selected tests' started at 2015-06-28 05:42:39 +0000
Test Suite 'DemoTests.xctest' started at 2015-06-28 05:42:39 +0000
Test Suite 'DemoTests' started at 2015-06-28 05:42:39 +0000
Test Case '-[DemoTests testPerformanceExample]' started.
/Users/huangwenchen/Desktop/Demo/DemoTests/DemoTests.m:41: Test Case '-[DemoTests testPerformanceExample]' measured [Time, seconds] average: 0.000, relative standard deviation: 40.714%, values: [0.000241, 0.000116, 0.000128, 0.000089, 0.000087, 0.000081, 0.000101, 0.000093, 0.000092, 0.000087], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: "", baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case '-[DemoTests testPerformanceExample]' passed (0.357 seconds).
Test Suite 'DemoTests' passed at 2015-06-28 05:42:40 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.358) seconds
Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:42:40 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.358) seconds
Test Suite 'Selected tests' passed at 2015-06-28 05:42:40 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 0.357 (0.360) seconds

异步測试

异步測试的逻辑例如以下。首先定义一个或者多个XCTestExpectation。表示异步測试想要的结果。然后设置timeout,表示异步測试最多能够执行的时间。

最后,在异步的代码完毕的最后。调用fullfill来通知异步測试满足条件。

- (void)testAsyncFunction{
XCTestExpectation * expectation = [self expectationWithDescription:@"Just a demo expectation,should pass"];
//Async function when finished call [expectation fullfill]
[self waitForExpectationsWithTimeout:10 handler:^(NSError *error) {
//Do something when time out
}];
}

举例

- (void)testAsyncFunction{
XCTestExpectation * expectation = [self expectationWithDescription:@"Just a demo expectation,should pass"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
NSLog(@"Async test");
XCTAssert(YES,"should pass");
[expectation fulfill];
});
[self waitForExpectationsWithTimeout:10 handler:^(NSError *error) {
//Do something when time out
}];
}

測试结果

Test Suite 'Selected tests' started at 2015-06-28 05:49:43 +0000
Test Suite 'DemoTests.xctest' started at 2015-06-28 05:49:43 +0000
Test Suite 'DemoTests' started at 2015-06-28 05:49:43 +0000
Test Case '-[DemoTests testAsyncFunction]' started.
2015-06-28 13:49:44.920 Demo[2157:145428] Async test
Test Case '-[DemoTests testAsyncFunction]' passed (1.006 seconds).
Test Suite 'DemoTests' passed at 2015-06-28 05:49:44 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 1.006 (1.007) seconds
Test Suite 'DemoTests.xctest' passed at 2015-06-28 05:49:44 +0000.
Executed 1 test, with 0 failures (0 unexpected) in 1.006 (1.009) seconds
Test Suite 'Selected tests' passed at 2015-06-28 05:49:44 +0000.

兴许:

计划下一篇会解说Mock 測试以及一些经常使用的Mock小工具。


iOS 单元測试之XCTest具体解释(一)的更多相关文章

  1. iOS单元測试:Specta + Expecta + OCMock + OHHTTPStubs + KIF

    框架选择 參考这篇选型文章,http://zixun.github.io/blog/2015/04/11/iosdan-yuan-ce-shi-xi-lie-dan-yuan-ce-shi-kuang ...

  2. ios单元測试之GHUnit

    1.相同创建一个測试的project, 2.通过cocoaPod来下载GHUnit框架,或者到github上下载.由于这个框架是开源的第三方框架. 同一时候加入QuartCore.framework( ...

  3. [iOS翻译]《iOS7 by Tutorials》在Xcode 5里使用单元測试(上)

    简单介绍: 单元測试是软件开发的一个重要方面.毕竟,单元測试能够帮你找到bug和崩溃原因,而程序崩溃是Apple在审查时拒绝app上架的首要原因. 单元測试不是万能的,但Apple把它作为开发工具包的 ...

  4. Android单元測试之JUnit

    随着近期几年測试方面的工作慢慢火热起来.常常看见有招聘測试project师的招聘信息.在Java中有单元測试这么一个JUnit 方式,Android眼下主要编写的语言是Java,所以在Android开 ...

  5. Android 进行单元測试难在哪-part3

    原文链接 : HOW TO MAKE OUR ANDROID APPS UNIT TESTABLE (PT. 1) 原文作者 : Matthew Dupree 译文出自 : 开发技术前线 www.de ...

  6. 【Android进阶】Junit单元測试环境搭建以及简单有用

    单元測试的目的 首先.Junit单元測试要实现的功能,就是用来測试写好的方法是否可以正确的运行,一般多用于对业务方法的測试. 单元測试的环境配置 1.在AndroidManifest清单文件的Appl ...

  7. 使用maven运行单元測试总结

    maven本身没有单元測试框架,可是maven的default生命周期的test阶段绑定了maven-surefire-plugin插件,该插件能够调用Junit3.Junit4.TestNG等Jav ...

  8. method initializationerror not found:JUnit4单元測试报错问题

           今天使用JUnit 4进行单元測试时,測试程序一直执行不起来,报method initializationerror not found错误.例如以下:            网上说版本 ...

  9. 利用Continuous Testing实现Eclipse环境自己主动单元測试

    当你Eclipse环境中改动项目中的某个方法时,你可能因为各种原因没有执行单元測试,结果代码提交,悲剧就可能随之而来. 所幸infinitest(http://infinitest.github.io ...

随机推荐

  1. c++中一个类所占用的空间

    看到阿里的一道笔试题: #pragma pack(2) class A { int i; union U { char buff[13]; int i; }u; void foo() { } type ...

  2. NodeJS会是昙花一现吗?

    在用了一年以后,我感觉node.js有一点不正确劲.它非常有意思,可是我认为我应该用另外一个视角去审视它. 网络编程真的能够更easy吗? node.js无疑有一些设计很好的地方.前段时间我写了一个性 ...

  3. Python 中的类的相关操作

    构造函数 构造函数是任何类都有的特殊方法.当要创建一个类时,就要调用构造函数.他的名字是__init__.init的前后分别是两个下划线.时间类Time的构造函数如下: >>> cl ...

  4. VM中装Linux换ISO文件报错"该光盘无法被挂载"

    一.发现问题 利用VM安装Red Hat Linux的时候,第一个iso安装完毕,准备换第二个iso,报错“该光盘无法被挂载”. 二.解决办法 上面的菜单栏中“虚拟机”—>“设置”—>“硬 ...

  5. IOS开发之UIView的基本使用

    一.视图 1. iphone手机上的窗口就是UIWindow类的一个实例(1个手机应用只有一个UIWindow). 2.UIView类用于实现视图. UIView提供了方法来添加和删除子视图.一个视图 ...

  6. vim: 远程登陆服务器时可能出现的: 方向键,回退符不能正常使用

    Solution of:远程登陆服务器时可能出现的: 方向键,回退符不能正常使用 远程登陆服务器,可能出现:方向键,回退符不能正常使用. 解决方法:在家目录下的.cshrc中添加set nocompa ...

  7. linux 进程线程拓展

    依次参考: 多线程和多进程的区别(小结) Linux内核源代码分析——fork()原理&多进程网络模型 Linux写时拷贝技术(copy-on-write) linux内核 do_fork 函 ...

  8. android multicast 多播(组播)问题

    有谁遇到过同样问题的可以探讨下,或者已经解决问题的,能够指导下我    获取组播锁 private  InetAddress   group; WifiManager  wm=(WifiManager ...

  9. Unity 3D 文件导入出错

    Unity 3D 文件导入出错 安装unity 时我选择了free版的,打开已有项目时出现例如以下错误提示 解决的方法: 先把要导入的文件先复制到unity3d安装文件夹下相应的文件夹内,之后再返回u ...

  10. 杭电 1711 Number Sequence

    Number Sequence Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...