swift - XCTest 何时启用和禁用 iCloud

标签 swift unit-testing icloud cloudkit xctest

我有一个 viewMode,它确定 iCloud 是启用还是禁用,结果是提示用户登录 iCloud。

有没有办法从 XCTest 以编程方式登录/注销 iCloud 以可靠地测试所有路径?

这是我的测试

func testShowLoginButtonForiCloud() {
  let viewModel = OnboardingViewModel()
  let expectation = XCTestExpectation(description: "Wait for CKContainer auth check")
  var iCloudEnabled: Bool?

  viewModel.shouldShowiCloudLogin { result, error in
    iCloudEnabled = result
    expectation.fulfill()
  }
  wait(for: [expectation], timeout: 5.0)

  XCTAssertNotNil(iCloudEnabled)
  XCTAssertFalse(iCloudEnabled!)
}

这是我的 View 模型

typealias Completion = (Bool, Error?) -> Void

final class OnboardingViewModel {
  func shouldShowiCloudLogin(completion: @escaping Completion) {
  CKContainer.default().accountStatus { (status, error) in
    switch status {
      case .available :
        completion(true, nil)
       default :
        completion(false, error)
      }
    }
  }
}

最佳答案

我们可以通过编程方式登录 CloudKit 进行单元测试吗?这是不可取的,因为即使我们可以,测试也会很慢且脆弱。相反,将 CloudKit 视为架构边界。单元测试可以一直到这个边界。我们可以假装东西从边界返回。这样,我们就可以测试所有路径了。

要将此边界编程到您的代码中,请使用协议(protocol)。该协议(protocol)将是一个仅包含您想要的那些 CKContainer 方法的切片。 (这是实际的接口(interface)隔离原则。)由于 CKContainer 已经实现了这个方法,我们可以将它附加为一个空扩展。

protocol CKContainerProtocol {
    func accountStatus(completionHandler: @escaping (CKAccountStatus, Error?) -> Void)
}

extension CKContainer: CKContainerProtocol {}

然后向您的 View 模型添加一个属性:

var cloudKitContainer: CKContainerProtocol = CKContainer.default()

默认值意味着您的代码将继续使用真正的 CKContainer,除非另有说明。更改您的代码以调用 cloudKitContainer 而不是 CKContainer.default()

然后在测试代码中,您可以提供 CKContainerProtocol 的不同实现。这会让你做 stub 和 mock 。您可以确认 accountStatus() 被调用了一次。您可以使用不同的 CKAccountStatus 值来执行它的闭包,以确认您的 Completion 闭包是如何被调用的。

关于swift - XCTest 何时启用和禁用 iCloud,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54240645/

相关文章:

android - 尝试使用 JUnit 测试库的考验

c# - 在 Visual Studio 中测试单独成功,在一组中失败

iphone - 使用此代码从iCloud备份中排除文件后,为什么我的应用程序仍然被拒绝?

java - Mockito:如果传递给 mock 的参数被修改了怎么办?

ios - swift ,Xcode 6 测试版 4 : How do I retrieve the file path of an image file that is currently being displayed using the Photos framework's assets?

ios - 如何在保存数据之前检查用户是否登录到 iCloud

ios - 如何在swift中加密sqlite数据

ios - 如何获取函数抛出的错误列表?

swift - 如何将图像连接到另一个 ViewController 并将其显示在 ImageView 中?

ios - Swift:UICollectionViewCell didSelectItemAtIndexPath 改变背景颜色