版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ginhoor/article/details/48290175
TDD(测试驱动开发 Test Driven Development),相比传统的开发流程,会先写测试,待测试通过再实际开发功能模块。这样的好处是在你使用这些已经测试过的功能时,不用担心他们的可用性。
BDD(行为驱动开发 Behavior Driven Development),相比TDD,相关测试代码更加集中,也更加简单易懂
相关链接:
TDD的iOS开发初步以及Kiwi使用入门
http://onevcat.com/2014/02/ios-test-with-kiwi/
Kiwi 使用进阶 Mock, Stub, 参数捕获和异步测试
http://onevcat.com/2014/05/kiwi-mock-stub-test/
PS:本文中主要介绍的是ReactiveCocoa的测试方法
使用OCUnit Test
1.模型测试
- (void)testPersonModel
{
NSString *string = @"{\"uname\":\"jack\",\"pic\":\"http://krplus-cdn.b0.upaiyun.com/common-module/common-header/images/logo.png\"}";
Person *a = [Person data:[string jsonDictionary]];
XCTAssertNotNil(a, @"model is nil");
XCTAssertNotNil(a.name, @"person has not a name!");
XCTAssertNotNil(a.avatar, @"person has not a avatar!");
}
2.接口测试。
- (void)testJsonAPI
{
// 使用 measureBlock 方法可以记录该测试的耗时
[self measureBlock:^{
NSString *urlStr = @"http://xiaoliao.sinaapp.com/index.php/Api369/index/pad/0/sw/1/cid/mm/lastTime/1441598591";
NSString *newUrlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:newUrlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *aString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
XCTAssertNotNil(aString, @"json is nil");
NSArray *jsonArray = [aString jsonArray];
XCTAssertNotNil(jsonArray, @"jsonArray is empty!");
[jsonArray enumerateObjectsUsingBlock:^(NSDictionary *json, NSUInteger idx, BOOL *stop) {
Person *a = [Person data:json];
XCTAssertNotNil(a, @"model is nil");
XCTAssertNotNil(a.name, @"person has not a name!");
XCTAssertNotNil(a.avatar, @"person has not a avatar!");
}];
}];
}
使用 kiwi框架
1.ViewModel的测试
SPEC_BEGIN(GinLoginViewModelSpec)
describe(@"GinLoginViewModel", ^{
__block GinLoginViewModel *loginVM;
//在scope内的每个it之前调用一次,对于context的配置代码应该写在这里
beforeEach(^{
loginVM = [[GinLoginViewModel alloc] init];
});
//在scope内的每个it之后调用一次,用于清理测试后的代码
afterEach(^{
loginVM = nil;
});
context(@"when username is 123456 and password is 123456", ^{
__block BOOL result = NO;
it(@"should return signal that value is NO", ^{
loginVM.username = @"123456";
loginVM.password = @"123456";
[[loginVM isValidUsernameAndPasswordSignal] subscribeNext:^(NSNumber *isValid) {
result = [isValid boolValue];
}];
[[theValue(result) should] beNo];
});
});
context(@"when username is 15558066089 and password is 123456", ^{
__block BOOL result = NO;
it(@"should return signal that value is YES", ^{
loginVM.username = @"15558066089";
loginVM.password = @"123456";
[[loginVM isValidUsernameAndPasswordSignal] subscribeNext:^(NSNumber *isValid)
{
result = [isValid boolValue];
}];
[[theValue(result) should] beYes];
});
});
});
SPEC_END
2.ViewController测试
SPEC_BEGIN(GinLoginViewControllerSpec)
describe(@"GinLoginViewController", ^{
__block GinLoginViewController *loginVC;
__block NSString *username = @"15558066089";
__block NSString *password = @"abc123456";
beforeEach(^{
loginVC = [[GinLoginViewController alloc] init];
[loginVC view];
});
afterEach(^{
loginVC = nil;
});
context(@"bind ViewModel", ^{
it(@"textfiled bind success", ^{
loginVC.username.text = username;
loginVC.password.text = password;
[loginVC.username sendActionsForControlEvents:UIControlEventEditingChanged];
[loginVC.password sendActionsForControlEvents:UIControlEventEditingChanged];
[[loginVC.loginVM.username should] equal:loginVC.username.text];
[[loginVC.loginVM.password should] equal:loginVC.password.text];
});
it(@"command bind success", ^{
[[loginVC.nextStep.rac_command should] equal:loginVC.loginVM.loginCommand];
});
});
});
SPEC_END