1. 程式人生 > >iOS 自動化單元測試--XCTest

iOS 自動化單元測試--XCTest

一、前言:

UITest的單元測試能最大限度的解放測試妹妹的雙手,當然也會給程式設計師帶來巨大工作量,完整的測試程式碼估計是專案程式碼的兩倍,另外大家可以自行百度 Xcode Coverage 檢視測試程式碼覆蓋率,這篇文章只講如何在工程中用XCTest框架做單元測試。
其中主要介紹了,用六個按鈕示意的UITests使用和效能測試、非同步測試的。

二、建立工程:

先建立個名字為 XCTest 的示例工程:
這裡寫圖片描述
這裡要說明一下如果當初建立工程時未勾選上Include Unit TestsInclude UI Test 這兩個複選框,可在專案工程targets目錄下手動建立 Tests 、UITests目標,如下圖示例:
這裡寫圖片描述

然後選中“iOS”在搜尋框裡輸入 test ,就能看到 “iOS UITesting Bundle”和 “iOS Unit Testing Bundle”兩個圖示了,選中後點擊“Next”按鈕後,就能在 TARGET 目錄下看到我們建立的測試項了。

這裡寫圖片描述

三、程式碼解釋:

1、接下來看看具體程式碼:
我們可以在 XCTests.m XCUITests.m 中發現一些共同的方法:

- (void)setUp {  …  }
- (void)tearDown {  …  }

2、方法的意義:
將要開始執行測試程式碼時呼叫: - (void)setUp { … }


測試程式碼執行完後呼叫,測試失敗不呼叫: - (void)tearDown { … }
其他任何方法都會在 - (void)setUp- (void)tearDown 呼叫。
所有的測試類類名都以Tests結尾,同樣類中所有的測試方法也都以- (void)test 開頭。

3、獲取app啟動物件:

[[[XCUIApplication alloc] init] launch];///為app物件分配記憶體並啟動它

4、其他:
UI測試示例程式碼:

XCUIElement *button1 = [[XCUIApplication alloc] init].buttons[@"1111"
];///獲取名字為2222的按鈕 XCTAssertTrue(button1.exists, @"'1111'按鈕存在");///#值為true才能通過,為false會停在這裡 [button1 tap];///觸發按鈕的點選事件

效能測試示例程式碼:

    NSLog(@"效能測試");
    [self measureBlock:^{  ///#用來分析程式碼執行的時間,log會列印在 console 裡,同時本地也會有一份日誌
        //例項化測試物件
        ///#測試那個類裡的方法就要引入那個類
        ViewController *vc = [[ViewController alloc] init];
        //#呼叫測試方法獲取測試結果
        [vc performanceExample];
    }];

非同步測試示例程式碼:
注意其中的“執行順序1、2、3、4”

 XCTestExpectation *expectation = [self expectationWithDescription:@"百度翻譯 測試"];
    NSLog(@"執行順序:1");
    ///請求引數
    NSMutableDictionary *paramer = [NSMutableDictionary dictionary];
    [paramer setValue:@"apple"  forKey:@"q"];
    [paramer setValue:@"en"     forKey:@"from"];
    [paramer setValue:@"zh"     forKey:@"to"];
    [paramer setValue:@"2015063000000001"   forKey:@"appid"];
    [paramer setValue:@"1435660288"         forKey:@"salt"];
    [paramer setValue:@"f89f9594663708c1605f3d736d01d2d4"     forKey:@"sign"];
    ///開始請求
    [ViewController networkRequestWithAPI:@"https://api.fanyi.baidu.com/api/trans/vip/translate" requestMethod:@"POST" cachePolicy:NSURLRequestUseProtocolCachePolicy requestParamer:paramer Completion:^(NSDictionary * _Nullable result, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        [expectation fulfill];///呼叫fulfill後 waitForExpectationsWithTimeout 會結束等待
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        XCTAssertTrue(httpResponse.statusCode==200, @"介面請求成功");///200表明http請求成功,請求失敗會停在這裡
        XCTAssertNotNil(result, @"json 物件不為空");///result結果為nil,會停在這裡
        XCTAssertNil(error, @"請求沒有出錯");//error 不為nil,會停在這裡
        NSLog(@"執行順序:3");
    }];
    NSLog(@"執行順序:2");
    ///因為介面設定的是30秒超時,所以這裡也設定30秒,意思就是這個執行緒最多等待30秒,
    [self waitForExpectationsWithTimeout:30.f handler:^(NSError * _Nullable error) {
        NSLog(@"執行順序:4");
        if (error) {
            ///測試程式碼無異常
        } else {
            ///測試程式碼有異常
        }
    }];

這裡寫圖片描述

這裡寫圖片描述

這裡寫圖片描述

四、圖示解釋:

1、測試前的圖示:
這裡寫圖片描述 這個圖標出現在所有以 - (void)test 開頭的方法前,這個是將要開始測試前的按鈕狀態圖示,一旦點選就開始測試這個方法裡的內容,或者我們也可以通過 command+U 的快捷鍵啟動完整測試,完整測試會執行 Tests 和 UITests 下所有的測試類和類中所有的測試方法。

2、測試成功圖示:
這裡寫圖片描述
綠色代表測試成功,同時xcode 也會彈框提示,
這裡寫圖片描述

3、測試失敗:
這裡寫圖片描述
表示某個測試方法測試失敗,同時程序也會停在測試未通過的程式碼那。
這裡寫圖片描述

4、錄製程式碼:
XCode為了方便我們進行自動化單元測試真是費勁了心思,當我們把滑鼠游標放到 -(void)testXXX {....} 這種測試方法裡後,能在XCode的工具條上看到紅色的按鈕,這個紅色的按鈕就是用來錄製程式碼。我們點選這個紅色按鈕後就會開始錄製程式碼,我們在app裡做任何操作都會在這裡產生測試程式碼。
這裡寫圖片描述
app越複雜,錄製程式碼時對電腦效能消耗就越高,一般8個G記憶體的蘋果電腦都很卡,甚至會讓 XCode 崩潰掉。我覺得錄製程式碼只適合幫助我們尋找app頁面上某個按鈕或者其他view,而關於這個按鈕或view的其他測試程式碼,需要我們手動去寫。

五、斷言註釋:

XCTFail(format…) //生成一個失敗的測試;
 XCTFail(@”Fail”);

 XCTAssertNil(a1, format…) //為空判斷, a1 為空時通過,反之不通過;
 XCTAssertNil(@”not nil string”, @”string must be nil”);

 XCTAssertNotNil(a1, format…) //不為空判斷,a1不為空時通過,反之不通過;
 XCTAssertNotNil(@”not nil string”, @”string can not be nil”);

 XCTAssert(expression, format…) //當expression求值為TRUE時通過;
 XCTAssert((2 > 2), @”expression must be true”);

 XCTAssertTrue(expression, format…) //當expression求值為TRUE時通過;
 XCTAssertTrue(1, @”Can not be zero”);

 XCTAssertFalse(expression, format…) //當expression求值為False時通過;
 XCTAssertFalse((2 < 2), @”expression must be false”);

 XCTAssertEqualObjects(a1, a2, format…) //判斷相等, [a1 isEqual:a2] 值為TRUE時通過,其中一個不為空時,不通過;
 XCTAssertEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return YES”);
 XCTAssertEqualObjects(@”1″, @”2″, @”[a1 isEqual:a2] should return YES”);

 XCTAssertNotEqualObjects(a1, a2, format…) //判斷不等, [a1 isEqual:a2] 值為False時通過,
 XCTAssertNotEqualObjects(@”1″, @”1″, @”[a1 isEqual:a2] should return NO”);
 XCTAssertNotEqualObjects(@”1″, @”2″, @”[a1 isEqual:a2] should return NO”);

 XCTAssertEqual(a1, a2, format…) //判斷相等(當a1和a2是 C語言標量、結構體或聯合體時使用,實際測試發現NSString也可以);
 XCTAssertNotEqual(a1, a2, format…) //判斷不等(當a1和a2是 C語言標量、結構體或聯合體時使用);

 XCTAssertEqualWithAccuracy(a1, a2, accuracy, format…) 判斷相等,(double或float型別)//提供一個誤差範圍,當在誤差範圍(+/- accuracy )以內相等時通過測試;
 XCTAssertEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return YES”);

 XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format…) 判斷不等,(double或float型別)//提供一個誤差範圍,當在誤差範圍以內不等時通過測試;
 XCTAssertNotEqualWithAccuracy(1.0f, 1.5f, 0.25f, @”a1 = a2 in accuracy should return NO”);

 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沒有發生具體異常、具體異常名稱的異常時通過測試,反之不通過;


 //下面介紹一下測試元素的語法

 XCUIApplication:
 //繼承XCUIElement,這個類掌管應用程式的生命週期,裡面包含兩個主要方法
 launch():
 //啟動程式
 terminate()
 //終止程式

 XCUIElement
 //繼承NSObject,實現協議XCUIElementAttributes, XCUIElementTypeQueryProvider
 //可以表示系統的各種UI元素
 .exist
 //可以讓你判斷當前的UI元素是否存在,如果對一個不存在的元素進行操作,會導致測試元件丟擲異常並中斷測試
 descendantsMatchingType(type:XCUIElementType)->XCUIElementQuery
 //取某種型別的元素以及它的子類集合
 childrenMatchingType(type:XCUIElementType)->XCUIElementQuery
 //取某種型別的元素集合,不包含它的子類

 //這兩個方法的區別在於,你僅使用系統的UIButton時,用childrenMatchingType就可以了,如果你還希望查詢自己定義的子Button,就要用descendantsMatchingType

 //另外UI元素還有一些互動方法
 tap()
 //點選
 doubleTap()
 //雙擊
 pressForDuration(duration: NSTimeInterval)
 //長按一段時間,在你需要進行延時操作時,這個就派上用場了
 swipeUp()
 //這個響應不了pan手勢,暫時沒發現能用在什麼地方,也可能是beta版的bug,先不解釋
 typeText(text: String)
 //用於textField和textView輸入文字時使用,使用前要確保文字框獲得輸入焦點,可以使用tap()函式使其獲得焦點

 XCUIElementAttributes協議
 //裡面包含了UIAccessibility中的部分屬性

五、示例工程 地址: