Ошибка тестирования при добавлении DispatchGroup

У меня есть несколько тестов, которые начали давать сбои с тех пор, как я представил DispatchGroup.

Пройдите простой тест, например:

  func test_loading_indicator_is_visible_only_when_loading_profile() {
    let (sut, spy) = makeSUT()
    let profile = makeProfile()
    let error = makeError()

    sut.loadViewIfNeeded()
    XCTAssertEqual(sut.isShowingLoadingIndicator, true)

    spy.loadProfileCompletes(with: .failure(error))
    XCTAssertEqual(sut.isShowingLoadingIndicator, false)

    sut.simulateRefresh()
    XCTAssertEqual(sut.isShowingLoadingIndicator, true)

    spy.loadProfileCompletes(with: .success(profile), at: 1)
    XCTAssertEqual(sut.isShowingLoadingIndicator, false)
  }
  1. Показывать индикатор загрузки при загрузке
  2. Скрыть при ошибке
  3. Потяните, чтобы снова обновить шоу
  4. Скрыть при успехе

Это работает на 100% без DispatchGroup.

Мне нужно запустить 2 асинхронных задачи во время этой загрузки, поэтому я подумал, что группа диспетчеризации будет идеальной, поскольку я могу дождаться обоих блоков завершения, прежде чем уведомить докладчика о завершении этой задачи.

Однако последнее утверждение всегда терпит неудачу, после некоторой отладки, которую я вижу в случае моего теста, событие успеха никогда не получено, что, в свою очередь, означает, что индикатор не удаляется.

Однако, запустив код в производственной среде, я вижу, что он действительно работает, поэтому я думаю, что это, возможно, связано с запуском в тестовом режиме.

Я удалил вторую задачу async, но оставил группу диспетчеризации на месте, чтобы посмотреть, изменилось ли это что-нибудь, а это не так.

Для наглядности сюда добавлена ​​группа отправки:

final class ProfileLoaderPresentationAdapter: ProfileRefreshViewControllerDelegate {
  var presenter: ProfilePresenter?
  private let profileLoader: ProfileLoader

  init(profileLoader: ProfileLoader) {
    self.profileLoader = profileLoader
  }

  func didRequestProfile() {
    presenter?.didStartLoading()
    profileLoader.load(then: { [weak self] result in
      switch result {
      case let .success(payload): self?.presenter?.didFinishLoading(with: payload.profile)
      case let .failure(error): self?.presenter?.didFinishLoading(with: error)
      }
    })
  }

}

Теперь это выглядит так:

final class ProfileLoaderPresentationAdapter: ProfileRefreshViewControllerDelegate {
  var presenter: ProfilePresenter?
  private let profileLoader: ProfileLoader

  init(profileLoader: ProfileLoader) {
    self.profileLoader = profileLoader
  }

  func didRequestProfile() {
    let taskGroup = DispatchGroup()
    var profile: Profile? = nil
    presenter?.didStartLoading()
    taskGroup.enter()
    profileLoader.load(then: { [weak self] result in
      switch result {
      case let .success(payload): profile = payload.profile
      case let .failure(error): self?.presenter?.didFinishLoading(with: error)
      }
      taskGroup.leave()
    })

    taskGroup.notify(queue: .main, execute: { [weak self] in
      guard let self = self, let profile = profile else { return }
      self.presenter?.didFinishLoading(with: profile)
    })
  }
}

Должен ли я делать что-нибудь еще, чтобы проверить этот код? У меня никогда раньше не было этой проблемы, правда, недавно я не тестировал так много, как сейчас (позор...)

редактировать

Мой шпион выглядит так:

  class LoaderSpy: ProfileLoader {

    enum Message: Equatable {
      case loadProfile
    }

    private(set) var messages: [Message] = []
    private var loadProfileCompletions: [(LoadProfileResult) -> Void] = []

    func load(then completion: @escaping (LoadProfileResult) -> Void) {
      messages.append(.loadProfile)
      loadProfileCompletions.append(completion)
    }

    func loadProfileCompletes(with result: LoadProfileResult, at index: Int = 0) {
      loadProfileCompletions[index](result)
    }
  }

0 ответов

Другие вопросы по тегам