Ошибка тестирования при добавлении 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)
}
- Показывать индикатор загрузки при загрузке
- Скрыть при ошибке
- Потяните, чтобы снова обновить шоу
- Скрыть при успехе
Это работает на 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)
}
}