XCTest для когда iCloud включен и отключен - PullRequest
0 голосов
/ 17 января 2019

У меня есть viewMode, который определяет, включен или отключен iCloud, в результате чего пользователю предлагается войти в iCloud или нет.

Есть ли способ программно войти / выйти из iCloud из XCTest для надежного тестирования всех путей?

Вот мой тест

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!)
}

Вот моя ViewModel

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)
      }
    }
  }
}

1 Ответ

0 голосов
/ 01 февраля 2019

Можем ли мы программно войти в CloudKit для модульного тестирования? Это нецелесообразно, потому что даже если бы мы могли, тесты были бы медленными и хрупкими. Вместо этого рассматривайте CloudKit как архитектурную границу. Модульные тесты могут идти прямо до этой границы. И мы можем притворяться, что вещи возвращаются с границы. Таким образом, мы можем проверить все пути.

Для программирования этой границы в вашем коде используйте протокол. Этот протокол будет слайсом, содержащим только те методы CKContainer, которые вы хотите. (Это принцип разделения интерфейса в действии.) Поскольку CKContainer уже реализует этот метод, мы можем присоединить его как пустое расширение.

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

extension CKContainer: CKContainerProtocol {}

Затем добавьте свойство к вашей модели представления:

var cloudKitContainer: CKContainerProtocol = CKContainer.default()

Значение по умолчанию означает, что ваш код будет продолжать использовать настоящий CKContainer, если не указано иное. Измените свой код так, чтобы звонить cloudKitContainer вместо CKContainer.default().

Затем в тестовом коде вы можете предоставить другую реализацию CKContainerProtocol. Это позволит вам делать заглушки и насмешки. Вы можете подтвердить, что accountStatus() вызывается ровно один раз. И вы можете использовать его замыкание с разными значениями CKAccountStatus, чтобы подтвердить, как вызывается ваше завершение Завершения.

(Подобные вещи будут подробно рассмотрены в книге по модульному тестированию iOS , которую я сейчас пишу .)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...