Swift单元测试从闭合内部抛出函数

时间:2018-01-16 04:38:05

标签: ios swift unit-testing firebase error-handling

我想为一个带有闭包的函数创建一个测试,它会抛出一个错误。进行此测试的最佳做法是什么?

Credential.swift

WITH pcd AS (
      SELECT *
      FROM ig_Dimension..Profit_Center_Dimension pcd
      WHERE (
            OR (pcd.profit_center_id = '13' AND csd.num_covers >= 10)
            OR (pcd.profit_center_id = 14 AND csd.num_covers >= 10)   -- is it an integer? or not?
            OR (pcd.profit_center_id = '26' AND csd.num_covers >= 10)
            OR (pcd.profit_center_id = '49' AND csd.num_covers >= 15)
            OR (pcd.profit_center_id = '57' AND csd.num_covers >= 10)
            OR (pcd.profit_center_id = '74' AND csd.num_covers >= 15)
            OR (pcd.profit_center_id = '77' AND csd.num_covers > 8)
            OR (pcd.profit_center_id = 90 AND csd.num_covers >= 10)   -- is it an integer? or not?
            OR (pcd.profit_center_id = 98 AND csd.num_covers >= 8)    -- is it an integer? or not?
            OR (pcd.profit_center_id = '194' AND csd.num_covers >= 10)
            OR (pcd.profit_center_id IN ('20', '21', '22', '200') AND csd.num_covers >= 8)
            OR (pcd.profit_center_id IN ('40', '41', '42', '43')  AND csd.num_covers >= 8)
            OR (pcd.profit_center_id IN ('60', '61', '62', '63', '64', '65') AND csd.num_covers > 16)
            OR (pcd.profit_center_id IN ('74', '101')      AND csd.num_covers >= 10)
            OR (pcd.profit_center_id IN ('86', '68')       AND csd.num_covers >= 8)
            OR (pcd.profit_center_id IN ('96', '98', '99') AND csd.num_covers >= 10)
            )
      AND pcd.ent_id = 1
      )
SELECT
      DATEPART(yyyy, csd.tendered_date_time) AS 'Year'
    , DATEPART(mm, csd.tendered_date_time)   AS 'Month'
    , pcd.[Profit Centre]
    , pcm.profit_center_name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               AS 'Profit Centre'
    , pcd.profit_center_id
    , COUNT(csd.num_covers)
FROM ig_business..Check_Sales_Detail csd
INNER JOIN pcd ON pcd.profit_center_dim_id = csd.profit_center_dim_id
INNER JOIN it_cfg..Profit_Center_Master pcm ON pcm.profit_center_id = pcd.profit_center_id
      AND pcm.ent_id = 1
GROUP BY GROUPING SETS
    (  DATEPART(yyyy, csd.tendered_date_time) AS 'Year'
    , DATEPART(mm, csd.tendered_date_time)   AS 'Month'
    , pcd.[Profit Centre]
    , pcm.profit_center_name                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               AS 'Profit Centre'
    , pcd.profit_center_id
    )

SignUpError.swift

class Credential {
    let email: String
    let password: String

    init(email: String, password: String) {
        self.email = email
        self.password = password
    }
} 

FirebaseController.swift

enum SignUpError: Error {
    case other(error: Error)
    case userAlreadyExist
}

FirebaseControllerTests.swift

typealias SignUpResult = (_ inner: () throws -> RebloodUser) -> Void
func signUp(_ credential: RebloodCredential, completionHandler: @escaping SignUpResult) {
    self.auth.createUser(withEmail: credential.email, password: credential.password) { (user: User?, error: Error?) in

        guard let user = user, error == nil else {
            completionHandler({ () -> RebloodUser in
                throw SignUpError.other(error: error!)
            })
            return
        }


        completionHandler({ () -> RebloodUser in
            let rebloodUser = RebloodUser(firebaseIdentifier: user.uid)
            return rebloodUser
        })

    }
}   

1 个答案:

答案 0 :(得分:0)

XCT提供XCTAssertNoThrowXCTAssertThrowsError来明确断言抛出或不抛出异常(更多内容,例如here)。

例如:XCTAssertNoThrow(try inner())

但是,如果您对表达式的结果更感兴趣(如在您的情况下返回的user)和期望那么该调用不应该抛出,您也可以忽略这些断言函数,而是使用try?和任何" normal"断言(例如XCTAssertEqual);如果异常被意外抛出,测试仍将中断,因为在这种情况下表达式将计算为nil并且比较断言将失败(除非您的测试期望nil为正确结果,在这种情况下变得更复杂,你必须明确检查没有抛出异常。)请注意,使用此代码,您将无法知道测试因异常而失败,还是因为返回的值无效。

例如:XCTAssertNotNil(try? inner().firebaseIdentifier)

注意这就是说,如果你不介意多写几行,你实施预测测试的方式也很好,而且肯定更灵活断言方法。

测试的另一个提示:假设FirebaseController.auth.createUser是一个异步方法,你应该使用XCT期望让测试等到调用回调:

func testControllerCanSignUp() {
    let exp = expectation(description: "callback called") // create the expectation
    controller.signUp(self.credential) { (inner: () throws -> RebloodUser) -> () in
        XCTAssertNotNil(try? inner().firebaseIdentifier)
        exp.fulfill() // tell the test that your expectation was fulfilled
    }
    waitForExpectations(timeout: 1, handler: nil) // let the test wait for up to one second to give your async code the chance to complete
}