Несколько асинхронных тестов и ожидание

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

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

Я просмотрел в Интернете "быстрые 3 множественных теста с ожиданием", и у каждого, кто объясняет ожидание, есть только пример в одном методе тестирования. Разве нельзя иметь ожидания от нескольких методов в одном классе?

Пример теста следующий:

func testLoginWrongUsernameOrPasswordFailure() {
  let viewModel = LoginViewModel()
  let loginAPI = APIManager()
  let expect = expectation(description: "testing for incorrect credentials")

  viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in

      do {
        try loginCompletion()
          XCTFail("Wrong Login didn't error")
          expect.fulfill()
        } catch let error {
          XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
          expect.fulfill()
        }
      })

      waitForExpectations(timeout: 10) { error in
        XCTAssertNil(error)
      }
}

Насколько я знаю, это правильное использование ожиданий, и каждый тест следует той же схеме

По просьбе Роба я предоставлю MCVE здесь https://bitbucket.org/chirone/mcve_test В тестовых классах используется фиктивный API-менеджер, но когда я тестировал реальный, ошибки все равно возникали.

В качестве объяснения для кода модель представления связывается с данным менеджером API, который вызывает сервер и возвращает ответ на модель представления для него, чтобы интерпретировать ошибки или успех.

Первый тест проверяет пустые поля, что проверяет модель представления, а не API Manager. Второй тест проверяет правильность имени пользователя и пароля Третий тест проверяет правильность имени пользователя и пароля

Три теста, запускаемые отдельно, будут работать нормально, однако при запуске всего файла я получу ошибку SIGABRT по следующим причинам:

Ошибка XCTAssertEqual: ("Необязательно (MCVE.LoginError.wrongCredentials)") не равно ("Необязательно (MCVE.LoginError.emptyFields)") -

*** Ошибка подтверждения в -[XCTestExpectation execute], /Library/Caches/com.apple.xbs/Sources/XCTest_Sim/XCTest-12124/Sources/XCTestFramework/Async/XCTestExpectation.m:101

*** Завершение работы приложения из-за необработанного исключения "NSInternalInconsistencyException", причина: "Нарушение API - сделано несколько вызовов -[XCTestExpectation execute] для проверки пустых полей".

SIGABRT обычно происходит во втором тестовом методе, и если вы нажмете кнопку play, то произойдет сбой в одном из методов XCTest, утверждая, что полученная ошибка не является ожидаемой.

Я надеюсь, что MCVE поможет объяснить мою проблему.

1 ответ

Если у вас есть несколько тестов (методов) в одном XCTestCase, не используйте

let expectation = expectation(description: "")

Вместо этого используйте

let expectation = XCTestExpectation(description: "")

В self.expectaion()используется совместно тестами XCTestCase. В некоторых случаях это приводит к странному поведению. Например, вы можете получить ошибку нарушения API, даже если вы выполнили ожидание ноль раз.

Рефакторинг кода приведен ниже.

func testLoginWrongUsernameOrPasswordFailure() {
  let viewModel = LoginViewModel()
  let loginAPI = APIManager()
  let expect = expectation(description: "testing for incorrect credentials")

  viewModel.loginWith(username: "qwerty", password: "qwerty", completion: { loginCompletion in

      do {
        try loginCompletion()
        XCTFail("Wrong Login didn't error")

      } catch let error {
        XCTAssertEqual(error as? LoginError, LoginError.wrongCredentials)
      }
      expect.fulfill()
   })

  waitForExpectations(timeout: 10) { error in
    XCTAssertNil(error)
  }
}

Если вы все еще получаете следующий сбой, это означает, что ваш обработчик завершения для асинхронного кода вызывает несколько раз. И там, вызывая функцию ожидаем. Несколько раз (). Что не разрешено.

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'API violation - multiple calls made to -[XCTestExpectation fulfill] for testing for empty fields.'

Для ожидания execute () должен вызываться только один раз. Если есть несколько редких сценариев, и вам нужно вызывать функцию ожидаем. Несколько раз () более одного раза, установите следующее свойство.

expectedFulfillmentCount

Пожалуйста, обратитесь по следующей ссылке https://developer.apple.com/documentation/xctest/xctestexpectation/2806572-expectedfulfillmentcount?language=objc

Можно ли ждать множественных ожиданий; да. Вот подпись для метода XCTestCase, который показывает это.

func wait(for: [XCTestExpectation], timeout: TimeInterval)

Существует версия, которая также обеспечивает выполнение ожиданий в том же порядке, в котором они отображаются в for: массив.

См. Документацию, предоставленную Apple, в XCode->Window->Documentation и API Reference, затем выполните поиск XCTestCase.

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