XCTest iOS Swift單元測試

ZY_FlyWay發表於2018-07-06

iOS XCTest單元格測試

XCTest iOS7的時候就接觸了,可是一直也沒用起來。起初的我覺得單元格測試純屬雞肋,我們只能測試單個類的一個函式,還要自己判斷期望的結果,進行驗證。如果依賴關係複雜,那麼就GG了。

成長是什麼呢,成長是在不同階段看待一個事物不同的看法。現在iOS 11了,從新再看到XCTest和新出的XCUITest,已不是當年的一臉嫌棄和不屑了。

記住一句話存在即合理。下面就是我從新花了1天時間學習路線(點開是連結地址):


認識 XCTest

新建專案的時候,Xcode都會問我們是否新建XCUnitTest和XCUITest。那麼XCUnitTest是幹什麼的呢,怎麼用呢,都包括什麼呢。

新建專案的Tests Target 檔案是這樣的:

import XCTest
@testable import XCTestDemo

class XCTestDemoTests: XCTestCase {

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}

從註釋我們可以知道這四個函式的意思:

函式 用途
setUp 繼承與XCTestCase 函式測試檔案開始執行的時候執行
tearDown 繼承與XCTestCase 測試函式執行完之後執行
testExample 測試的例子函式
testPerformanceExample 效能測試

下面XCTest 使用簡單的例子

看了應該明白怎麼用了


//
//  XCTestDemoTests.swift
//  XCTestDemoTests
//
//  Created by Nvr on 2018/7/6.
//  Copyright © 2018年 ZY. All rights reserved.
//

import XCTest
@testable import XCTestDemo

class XCTestDemoTests: XCTestCase {

    var f1:Float?
    var f2:Float?

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
        f1 = 10.0
        f2 = 20.0
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
        XCTAssertTrue(f1! + f2! == 30.0)
    }

    //simpale Test
    func testIsPrimenumber()  {
        let oddNumber = 5
        //There are lot XCTAssert function, you can check it
        XCTAssertTrue(isPrimenumber(number: Double(oddNumber)))
    }

    func isPrimenumber(number:Double) -> Bool{
        for No in 1...Int(sqrt(number)) {
            if Int(number)/No != 0 {
                return true
            }
        }
        return false
    }

    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}

例子說明:

函式 說明
testExample 全域性變數f1 + f2 相加是否等於固定的數,斷言是否相等
testIsPrimenumber 判斷是否是素數 斷言是否返回真

總結:通過上面的兩個例子,應該明白了XCUintTest是幹什麼,怎麼用的啦。

斷言常用API:

API 說明
XCTFail(…) 任何嘗試都會測試失敗,…是輸出的提示文字。(後面都是這樣)
XCTAssertNil(expression, …) expression為空時通過,否則測試失敗。 expression接受id型別的引數。
XCTAssertNotNil(expression, …) expression不為空時通過,否則測試失敗。expression接受id型別的引數。
XCTAssert(expression, …) expression為true時通過,否則測試失敗。expression接受boolean型別的引數。
XCTAssertTrue(expression, …) expression為true時通過,否則測試失敗。expression接受boolean型別的引數。
XCTAssertFalse(expression, …) expression為false時通過,否則測試失敗。expression接受boolean型別的引數。
XCTAssertEqualObjects(expression1, expression2, …) expression1和expression1地址相同時通過,否則測試失敗。expression接受id型別的引數。
XCTAssertNotEqualObjects(expression1, expression2, …) expression1和expression1地址相同時通過,否則測試失敗。expression接受id型別的引數。
XCTAssertEqual(expression1, expression2, …) expression1和expression1相等時通過,否則測試失敗。expression接受基本型別的引數(數值、結構體之類的)。
XCTAssertNotEqual(expression1, expression2, …) expression1和expression1不相等時通過,否則測試失敗。expression接受基本型別的引數。
XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, …) expression1和expression2之間的任何值都大於accuracy時,測試失敗。expression1、expression2、accuracy都為基本型別。
XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, …) expression1和expression2之間的任何值都小於等於accuracy時,測試失敗。expression1、expression2、accuracy都為基本型別。
XCTAssertGreaterThan(expression1, expression2, …) expression1 <= expression2時,測試失敗。expression為基本型別
XCTAssertGreaterThanOrEqual(expression1, expression2, …) expression1 < expression2時,測試失敗。expression為基本型別
XCTAssertLessThan(expression1, expression2, …) expression1 >= expression2時,測試失敗。 expression為基本型別
XCTAssertLessThanOrEqual(expression1, expression2, …) expression1 > expression2時,測試失敗。 expression為基本型別
XCTAssertThrows(expression, …) expression沒拋異常,測試失敗。expression為一個表示式
XCTAssertThrowsSpecific(expression, exception_class, …) expression沒拋指定類的異常,測試失敗。expression為一個表示式,exception_class為一個指定類
XCTAssertThrowsSpecificNamed(expression, exception_class, exception_name, …) expression沒拋指定類、指定名字的異常,測試失敗。expression為一個表示式exception_class為一個指定類,exception_name為一個指定名字
XCTAssertNoThrow(expression, …) expression丟擲異常時,測試失敗。expression為一個表示式
XCTAssertNoThrowSpecific(expression, exception_class, …) expression丟擲指定類的異常,測試失敗。expression為一個表示式
XCTAssertNoThrowSpecificNamed(expression, exception_class, exception_name, …) expression丟擲指定類、指定名字的異常,測試失敗。

非同步測試

下面一些情況會用到非同步測試:

  • 開啟文件
  • 在其他執行緒工作
  • 和服務或者擴充套件進行交流
  • 網路活動
  • 動畫
  • UI測試的一些條件

網路請求非同步Case

關於UI的非同步測試在下篇XCUITest中說,一個網路請求的Case可以說明白非同步測試的機制。

  1. pod匯入alamofire,Target是你要測試的tests Target.
  2. 新建期望,用alamofire 發起請求。
  3. 請求回撥裡斷言是否為空,fullfill期望看是否滿足期望
  4. XCWaiter設定期望完成的時間
func testAsynNetworkTest(){

        let networkExpection = expectation(description: "networkDownSuccess")

        Alamofire.request("http://www.httpbin.org/get?key=Xctest", method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON { (respons) in
            XCTAssertNotNil(respons)
            networkExpection.fulfill()
        }


//        waitForExpectations(timeout: 0.00000001)
//        wait(for: [networkExpection], timeout: 0.00000001)


//XCTWaiter.Result  列舉型別如下
//        public enum Result : Int {
//
//
//            case completed
//
//            case timedOut
//
//            case incorrectOrder
//
//            case invertedFulfillment
//
//            case interrupted
//        }
        let result = XCTWaiter(delegate: self).wait(for: [networkExpection], timeout:  1)
        if result == .timedOut {
            print("超時")
        }
    }

說明:下面三個函式都是設定XCWaiter等待期望時間,只是細節不同。

函式
waitForExpectations(timeout: 0.00000001)
wait(for: [networkExpection], timeout: 0.00000001)
let result = XCTWaiter(delegate: self).wait(for: [networkExpection], timeout: 0.00000001)

Mock

重點來了,我一直

相關文章