Swift 中的单元测试 HKSampleQuery

Posted

技术标签:

【中文标题】Swift 中的单元测试 HKSampleQuery【英文标题】:Unit Test HKSampleQuery in Swift 【发布时间】:2015-12-01 15:02:18 【问题描述】:

当我需要从 HealthKit 读取数据时,我的代码如下所示:

let stepsCount = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount)

let stepsSampleQuery = HKSampleQuery(sampleType: stepsCount,
    predicate: nil,
    limit: 100,
    sortDescriptors: nil)
     [unowned self] (query, results, error) in
        if let results = results as? [HKQuantitySample] 
            self.steps = results
            // Update some UI
        
        self.activityIndicator.stopAnimating()


healthStore?.executeQuery(stepsSampleQuery)

此特定代码是从here 中提取的,用于演示目的。

所以我的问题是:

如何对这种代码进行单元测试?

【问题讨论】:

【参考方案1】:

我将此代码封装在模型类中的一个函数中,该模型类对 UI 一无所知。它的工作原理是这样的:

在你有你的地方

// Update some UI

调用一个使用参数传递给函数的完成闭包。

你可以像这样从你的控制器类调用这个函数

hkModel.selectSteps() 
    [unowned self] (query, results, error) in
    // update UI

这样您就可以将模型类中的查询逻辑与您的 UIController 代码完全分开。

现在您可以轻松编写调用相同方法的单元测试:

func testSteps() 
    hkModel.selectSteps() 
        [unowned self] (query, results, error) in
        // XCTAssert(...)
    

您需要做的最后一件事是尊重您的测试代码是异步调用的:

let stepExpectationEnd = expectationWithDescription("step Query")
hkModel.selectSteps() 
    [unowned self] (query, results, error) in
    // XCTAssert(...)
    stepExpectationEnd.fulfill()

waitForExpectationsWithTimeout(10.0) 
    (error: NSError?) in
     if let error = error 
         XCTFail(error.localizedDescription)
     

更新

因为你问:

我在测试设置中处理授权。看起来像这样:

var healthData: HealthDataManager?
override func setUp() 
    super.setUp()
    healthData = HealthDataManager()
    XCTAssert(healthData != nil, "healthDadta must be there")

    let authorizationAndAScheduleExpectation = expectationWithDescription("Wait for authorizatiion. Might be manual the first time")
    healthData?.authorizeHealthKit( (success: Bool, error: NSError?) -> Void in
        print ("success: \(success) error \(error?.localizedDescription)")
        // fails on iPad
        XCTAssert(success, "authorization error \(error?.localizedDescription)")

        self.healthData?.scheduleAll() 
            (success:Bool, error:ErrorType?) -> Void in
            XCTAssert(success, "scheduleAll error \(error)")

            authorizationAndAScheduleExpectation.fulfill()
        
    )
    waitForExpectationsWithTimeout(60.0) 
        error in
        if let error = error 
            XCTFail(error.localizedDescription)
        
    

第一次在模拟器中运行此代码时,您必须手动批准授权。

第一次运行后,测试无需人工干预即可运行。

【讨论】:

这种方法看起来很有趣,但我有两个主要问题: 1- 测试目标如何处理 healthkit 自动化? . 2- 我们到底在测试什么,因为 stepsCount 是模拟器或测试目标不跟踪的东西?我应该模拟一些数据吗?这里有什么想法或建议吗? 第 1 部分:我更新了我的官方答案。第 2 部分:您的模拟器中有一个健康应用程序。在您的模拟器中打开此健康应用程序并使用它为步骤添加数据点:健康应用程序 -> 健身 -> 步骤 -> 添加数据点 谢谢,这太棒了。 你真的希望你的单元测试依赖于手动输入健康包数据到模拟器吗?对我来说听起来真的很不稳定。所有模拟器、开发人员和 CI 系统都需要这样做。话虽如此,我只是未能模拟 HealthKit 数据。 第一次必须手动授权。据我所知,没有办法解决这个问题。第一次之后就不需要了。

以上是关于Swift 中的单元测试 HKSampleQuery的主要内容,如果未能解决你的问题,请参考以下文章

无法在单元测试项目中的 Swift 中读取 JSON 文件

比较单元测试中的 swift Type 值 - XCTAssertEqual vs ==

swift in UI test(测试UITableView中的单元格数)

单元测试 WKNavigationDelegate 函数 swift

Swift之深入解析如何避免单元测试中的强制解析

Swift 中的单元测试 | IOS 故事板 |无法转换目标 c 中定义的视图控制器类