Задержка в модульном тесте - PullRequest
0 голосов
/ 26 апреля 2019

Итак, у меня есть модульный тест, чтобы проверить, обновляются ли клиники каждые 10 секунд. Через 5 секунд я очищаю все клиники. Затем установите ожидаемое время ожидания через 9 секунд, чтобы убедиться, что клиники были обновлены. Вот мой код:

func testRefresh() {

    let expec = expectation(description: "Clinics timer expectation")
    let expec2 = expectation(description: "Clinics timer expectation2")
    expec2.isInverted = true
    let dispatchGroup = DispatchGroup(count: 5)

    dataStore.load()

    wait(for: [expec2], timeout: 5.0) // This is what I am asking about
    self.dataStore.clinicsSignal.fire([])

    dataStore.clinicsSignal.subscribeOnce(with: dispatchGroup) {
        print("clinics signal = \($0)")
        expec.fulfill()
    }

    wait(for: [expec], timeout: 9.0)
    XCTAssertFalse(self.dataStore.clinics.isEmpty)
}

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

Если я использую sleep(5), это останавливает всю программу на 5 секунд. Я также попытался найти решение, используя DispatchQueue.main.asyncAfter, как указано здесь , но безрезультатно.

1 Ответ

1 голос
/ 29 апреля 2019

У меня есть два предложения для совместного использования:

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

Двойной шпионский тест

Тестирование побочного эффекта загрузки данных, который попадает в сервис, может стать способом упростить ваш тест.

Вместо того, чтобы использовать разные ожидания и испытывать тестируемую систему таким образом, чтобы это не могло быть тем, что происходит во время выполнения (dataStore.clinicsSignal.fire([])), вы можете просто посчитать, сколько раз был запущен сервис, и установить значение 2.

Интервал обновления ввода

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

В конце концов, я предполагаю, что вас интересует то, что код обновления работает, как ожидается, а не каждые 10 секунд. То есть он должен обновляться с установленной вами частотой.

Это можно сделать, указав значение по умолчанию в инициализации вашего хранилища данных, а затем переопределить его в тестах.

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

Собираем все вместе, что-то более или менее подобное

protocol ClinicsService {
  func loadClinics() -> SignalProducer<[Clinics], ClinicsError>
}

class DataSource {

  init(clinicsService: ClinicsService, refreshInterval: TimeInterval = 5) { ... }
}

// in the tests

class ClinicsServiceSpy: ClinicsService {

  private(var) callsCount: Int = 0

  func loadClinics() -> SignalProducer<[Clinics], ClinicsError> {
    callsCount += 1
    // return some fake data
  }
}

func testRefresh() {
  let clinicsServiceSpy = ClinicsServiceSpy()
  let dataStore = DataStore(clinicsService: clinicsServiceSpy, refreshInterval: 0.05)

  // This is an async expectation to make sure the call count is the one you expect
  _ = expectation(
    for: NSPredicate(
    block: { input, _ -> Bool in
      guard let spy = input as? ClinicsServiceSpy else { return false }
      return spy.callsCount == 2
    ),
    evaluatedWith: clinicsServiceSpy,
    handler: .none
  )

  dataStore.loadData()

  waitForExpectations(timeout: .2, handler: nil)
}

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

func testRefresh() {
  let clinicsServiceSpy = ClinicsServiceSpy()
  let dataStore = DataStore(clinicsService: clinicsServiceSpy, refreshInterval: 0.05)

  dataStore.loadData()

  expect(clinicsServiceSpy.callsCount).toEventually(equal(2))
}

Компромисс, который вы делаете в этом подходе, состоит в том, чтобы сделать тест более простым, написав немного больше кода. Решите, хороший ли это компромисс.

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

Дайте мне знать, что вы думаете.

...