1. 程式人生 > >關於iOS TDD&BDD的學習與使用

關於iOS TDD&BDD的學習與使用

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