Тестирование ViewModel в RxSwift
Я хотел бы выполнить тест в одном из моих ViewModels, который содержит объект BehaviorRelay с именем "nearByCity", который привязан к BehaviorRelay с именем "isNearBy". Вот так выглядит моя модель зрения.
class SearchViewViewModel: NSObject {
//MARK:- Properties
//MARK: Constants
let disposeBag = DisposeBag()
//MARK: Vars
var nearByCity:BehaviorRelay<String?> = BehaviorRelay(value: nil)
var isNearBy = BehaviorRelay(value: true)
//MARK:- Constructor
init() {
super.init()
setupBinders()
}
}
//MARK:- Private methods
private extension SearchViewViewModel{
func setupBinders(){
nearByCity
.asObservable()
.distinctUntilChanged()
.map({$0 ?? ""})
.map({$0 == ""})
.bind(to: isNearBy)
.disposed(by: disposeBag)
}
}
Тест, который я хочу выполнить, состоит в том, чтобы фактически проверить, что, когда строка принята, значение bool также изменяется в соответствии с функцией setupBinders().
Любая идея?
Спасибо
1 ответ
Вот один из способов проверить:
class RxSandboxTests: XCTestCase {
func testBinders() {
let scheduler = TestScheduler(initialClock: 0)
let source = scheduler.createColdObservable([.next(5, "hello"), .completed(10)])
let sink = scheduler.createObserver(Bool.self)
let disposeBag = DisposeBag()
let viewModel = SearchViewViewModel(appLocationManager: StubManager())
source.bind(to: viewModel.nearByCity).disposed(by: disposeBag)
viewModel.isNearBy.bind(to: sink).disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(sink.events, [.next(0, true), .next(5, false)])
}
}
Некоторые другие моменты:
Не делайте ваши предметные свойства
var
использованиеlet
вместо этого, потому что вы не хотите, чтобы кто-либо мог заменить их несвязанными версиями.Тот факт, что вы должны использовать
AppLocationManager
в этом коде, который не нуждается в этом, подразумевается, что объект делает слишком много. Нет ничего плохого в наличии нескольких моделей представлений в контроллере представлений, каждая из которых обрабатывает разные части представления.Лучше всего вообще избегать использования объектов (реле) в коде модели представления, при необходимости их лучше оставлять в императивной части кода.
Как минимум, разбейте функцию setupBinders, чтобы детали могли быть независимо проверены. Выше можно было написать как простую, легко тестируемую бесплатную функцию:
func isNearBy(city: Observable<String?>) -> Observable<Bool> {
return city
.distinctUntilChanged()
.map {$0 ?? ""}
.map {$0 == ""}
}