你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS --- 使用XCTest進行單元測試

iOS --- 使用XCTest進行單元測試

編輯:IOS開發綜合

測試驅動開發(TDD)是當前流行的開發理念,XCTest是Apple封裝的單元測試類庫。使用XCTest進行單元測試的流程比較簡單,本博客僅簡單介紹下XCTest的使用。但對於單元測試的理解(何時使用,如何更高效地驅動開發)卻是一個需要積累的過程,要在TDD的過程中仔細體會。

setUp和tearDown

一個測試用例以一個Objective-C類的形式存在,其implementation中有默認的setUp和tearDown方法,分別用於處理用例執行前的准備工作和執行完畢後的清理工作。

- (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];
}

因此,常在setUp中進行基本對象的初始化等一些必需的步驟。

單元測試

所有以test開頭的實例方法(不能有參數)都是一個完整的單元測試的case。

這裡寫圖片描述

最左邊有個小圖標,點擊之後即可執行該測試case。

性能測試

性能測試可直接使用 - (void)measureBlock:(void (^)(void))block; 進行,傳遞參數即為要執行任務組成的一個block。
如以下的case可用於測試measureBlock接收的block參數中執行的性能。

這裡寫圖片描述

Baseline即可設置該性能是否合格的參考基准。
注意,一個性能測試case中只能執行一次measureBlock,即只能測試一個指定block步驟的性能(這其實也是合乎情理的,混到一塊了哪裡還能區分出性能測試的結果)。因此,在while,for等循環中是不能使用measureBlock的,否則會出錯。
measureMetrics的用法跟measureBlock類似。
當然,也可以使用startMeasuring和stopMeasuring方法進行性能測試,但絕大多數情況下使用measureBlock已經足夠了。

性能測試的宏定義

例如,在單獨測試一個圖片濾鏡的性能時,可以這樣:

- (void)testPerformanceFilter1 {
    [self measureBlock:^{
        NSInteger filterid = 100;
        UIImage *filteredImage = [FilterTool filterImage:self.image withFilterId:filterid];
        XCTAssertNotNil(filteredImage, @"濾鏡效果圖應該非空");
    }];
}

那麼,如果有幾十個濾鏡需要進行性能測試呢?
因為單元測試case的方法名不能傳遞參數,且循環中不能使用measureBlock,因此對於大量重復的性能測試case,目前看來采用宏定義是比較好的解決方法。

#define TestFilterPerformance(filterid) - (void)testFilterPerformance_##filterid { \
    [self measureBlock:^{ \
        UIImage *filteredImage = [FilterTool filterImage:self.image withFilterId:filterid]; \
        XCTAssertNotNil(filteredImage, @"濾鏡效果圖應該非空"); \
    }]; \
}

則使用起來,就可如下定義所有的測試case了。

這裡寫圖片描述

異步測試

XCTest提供了XCTestExpectation來進行異步測試,即可在指定時機使用其fulfill實例方法開始執行斷言命令。例如以下是一個完整的網絡請求的測試樣例,可用於測試server端是否正常,要在對應的block中進行斷言。

- (void)testAsynchronousURLConnection {
    XCTestExpectation *expectation = [self expectationWithDescription:@"GET Baidu"];

    NSURL *url = [NSURL URLWithString:@"http://www.baidu.com/"];
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        // XCTestExpectation條件已滿足,接下來的測試可以執行了。
        [expectation fulfill];
        XCTAssertNotNil(data, @"返回數據不應非nil");
        XCTAssertNil(error, @"error應該為nil");
        if (nil != response) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            XCTAssertEqual(httpResponse.statusCode, 200, @"HTTPResponse的狀態碼應該是200");
            XCTAssertEqual(httpResponse.URL.absoluteString, url.absoluteString, @"HTTPResponse的URL應該與請求的URL一致");
        } else {
            XCTFail(@"返回內容不是NSHTTPURLResponse類型");
        }
    }];
    [task resume];

    // 超時後執行
    [self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
        [task cancel];
    }];
}

即:異步網絡請求操作正常執行,但斷言命令僅在[expectation fulfill];結束後才開始執行,這樣能確保得到網絡請求的返回結果後執行相應斷言。同時,可設置超時時間及對應操作。
否則,就需要使用定時機制等處理類似情況。

訪問待測類的私有變量

在case中,如何訪問一個待測類的私有變量呢?對該類進行相應的擴展即可。

#import 
#import "FilterTool.h"

@interface FilterTool (UnitTest)

@property (strong, nonatomic) FilterController *filterController;

- (void)didSelectFilterCellAtIndexPath:(NSIndexPath *)indexPath;

@end


@interface FilterToolTest : XCTestCase

@end

@implementation FilterToolTest

XXXX

@end

FilterTool類的filterController屬性和didSelectFilterCellAtIndexPath:方法本是私有的,若想對其進行測試,則必須將其加入擴展。

斷言命令

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)以內相等時通過測試;

XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...) 判斷不等,(double或float類型)提供一個誤差范圍,當在誤差范圍以內不等時通過測試;

XCTAssertThrows(expression, format...)異常測試,當expression發生異常時通過;反之不通過;(很變態)

XCTAssertThrowsSpecific(expression, specificException, format...) 異常測試,當expression發生specificException異常時通過;反之發生其他異常或不發生異常均不通過;

XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)異常測試,當expression發生具體異常、具體異常名稱的異常時通過測試,反之不通過;

XCTAssertNoThrow(expression, format…)異常測試,當expression沒有發生異常時通過測試;

XCTAssertNoThrowSpecific(expression, specificException, format...)異常測試,當expression沒有發生具體異常、具體異常名稱的異常時通過測試,反之不通過;

XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)異常測試,當expression沒有發生具體異常、具體異常名稱的異常時通過測試,反之不通過.
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved