写在前面
单元测试的重要性,不言而喻,在迭代开发 Framework 的过程中,好的单元测试,能及早发现问题。
关于 iOS Framework 的单元测试,常见的工具,当属官方提供的 XCTests,但它也有些局限,所以笔者写了个小工具,对其进行补充。
本文会简单介绍 XCTests 的使用。
创建工程
新建一个 SDKDemo 工程,记得勾上 Include Unit Tests
生成工程如图,会有一个SDKDemoTests
的 Target 和相应的目录
新建 NetworkRequest,作为测试对象,代码如下:
@interface NetworkRequest : NSObject
- (BOOL)configure;
@end
@implementation NetworkRequest
- (BOOL)configure {
return YES;
}
@end
使用 XCTests 进行单元测试
在新建模板里选择 Unit Tests Case Class
,创建 NetworkRequestTests
如图:
添加代码:
#import <XCTest/XCTest.h>
#import "NetworkRequest.h"
@interface NetworkRequestTests : XCTestCase
@property (nonatomic, strong) NetworkRequest *request;
@end
@implementation NetworkRequestTests
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.request = [NetworkRequest new];
}
- (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.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
// 添加的测试方法
- (void)testConfigure {
XCTAssertTrue([self.request configure]);
}
@end
对于每个 test 开头的方法,Xcode 会在其左边显示一个圆点,点一下它,就可以运行这个测试方法,使用快捷键 command+u 会执行所有测试。
同时 XCTests 提供许多断言,如上面使用的 XCTAssertTrue。
当断言成立时,圆点会显示为绿色,否则为红色。
若有 Block,如何测试?
在 NetworkRequest 中添加代码:
@interface NetworkRequest : NSObject
- (void)loginWithCompletionHandler:(void (^)(BOOL success))handler;
@end
@implementation NetworkRequest
- (BOOL)configure {
return YES;
}
- (void)loginWithCompletionHandler:(void (^)(BOOL))handler {
NSLog(@"Begin login");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
handler(YES);
});
}
@end
对于 Block 的测试,得使用 XCTestExpectation
,并且在 Block 里调用 fullfill
方法。否则测试不会等到 Block 执行,就直接退出。
测试代码:
@implementation NetworkRequestTests
- (void)testLogin {
// 声明一个 XCTestExpectation 对象
XCTestExpectation *expectation = [[XCTestExpectation alloc] initWithDescription:@"login expectation"];
[self.request loginWithCompletionHandler:^(BOOL success) {
XCTAssertTrue(success);
// 调用 fullfill,告知 XCTestExpectation 已出现
[expectation fulfill];
}];
// 等待 XCTestExpectation
[self waitForExpectationsWithTimeout:5 handler:nil];
}
@end
代码覆盖率
默认没有打开,可以编辑 Test Scheme,如图,勾选该功能
勾选 code coverage
再次运行测试,然后如图,查看结果
codeCoverageResult.png
如何在单元测试中引用 Framework?
在开发 Framework 过程中,典型场景就是 A 引用了 B,对 A 进行测试时,正如下文所说的
Because unit test targets are missing the Linked Frameworks and Libraries section in their General settings tab, you must instead drag the built frameworks to the Link Binaries With Libraries build phase.
这种情况下,无法进行测试,这也是笔者一开始想要对 XCTests 进行补充的初衷。
但后来发现
In the Test target under the Build Settings tab, add @loader_path/Frameworks to the Runpath Search Paths if it isn't already present.
还是有解决方案的。
扩展
XCTests 作为官方提供的测试方法,上手简单,十分适合用来做单元测试。
美中不足的是,XCTests 不支持真机测试,所以有些功能无法测试,也无法在真机上测试性能。
这种情况下,又该如何处理,请看《iOS Framework 单元测试(二)-- JDAppTests(XCTests的补充)》
网友评论