У меня есть два предложения для совместного использования:
- Используйте двойной тест шпион , чтобы убедиться, что служба, используемая вашим хранилищем данных для обновления клиник, вызывается дважды
- Введите интервал обновления, чтобы ускорить тестирование
Двойной шпионский тест
Тестирование побочного эффекта загрузки данных, который попадает в сервис, может стать способом упростить ваш тест.
Вместо того, чтобы использовать разные ожидания и испытывать тестируемую систему таким образом, чтобы это не могло быть тем, что происходит во время выполнения (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))
}
Компромисс, который вы делаете в этом подходе, состоит в том, чтобы сделать тест более простым, написав немного больше кода. Решите, хороший ли это компромисс.
Мне нравится работать таким образом, потому что он защищает каждый компонент в моей системе от неявных зависимостей, и тест, который я в итоге пишу, легко читается и работает как живая документация для программного обеспечения.
Дайте мне знать, что вы думаете.