mardi 14 mars 2017

How to test a combineLatest observable with RxTest?

So I have this viewModel which has a validation observable that is simply the combination of 5 other signals into a boolean.

import RxSwift

class SchedulingFormViewModel: BaseViewModel {

    let places = Variable<[String]>([])

    var formIsValid: Observable<Bool>!

    override init() {
        super.init()
        places.value = ["LUGAR 1", "LUGAR 2", "LUGAR 3"]

        formIsValid = Observable.combineLatest(UserSession.currenctScheduling.dateSignal.asObservable(),
                                               UserSession.currenctScheduling.carSignal.asObservable(),
                                               UserSession.currenctScheduling.locationSignal.asObservable(),
                                               UserSession.currenctScheduling.servicesSignal.asObservable())
        { (date: Date?, car: Car?, location: String?, services: [Service]?) in
            print("DATE: \(date), CAR: \(car), LOCATION: \(location), SERVICES:\(services)")
            guard let servicesArray = services else { return false }
            let valid = date != nil && car != nil && location != nil && servicesArray.count > 0
            return valid
        }
    }
}

And then I have my test class with a method that should just test whether the signal changes or not. I've tried a variety of approaches but none of them really gets the true value at the end. The observable only emits a true signal after the test has run.

My test class is setup like this

import XCTest

import RxSwift
import RxTest

@testable import Automobi

class SchedulingUnitTests: XCTestCase {

    var viewModel: SchedulingFormViewModel!
    var disposeBag: DisposeBag!
    var scheduler: TestScheduler!

    override func setUp() {
        super.setUp()
        viewModel = SchedulingFormViewModel()
        UserSession.clearScheduling()
        disposeBag = DisposeBag()
        scheduler = TestScheduler(initialClock: 0) 
    }
}

I've tried the TestScheduler

func testFormValidation() {
    UserSession.currenctScheduling.dateSignal.value = Date()
    UserSession.currenctScheduling.carSignal.value = Car()
    UserSession.currenctScheduling.servicesSignal.value = [Service(), Service()]

    let location = scheduler.createHotObservable([
        next(100, "TEST")
    ])

    location.subscribe(onNext: { (text) in
        print("LOCATION: \(text)")
        UserSession.currenctScheduling.locationSignal.value = text
    }).addDisposableTo(disposeBag)


    let results = scheduler.createObserver(Bool.self)

    scheduler.scheduleAt(0) { 
        self.viewModel.formIsValid.subscribe(results).addDisposableTo(self.disposeBag)
    }

    let expected = [
        next(100, true)
    ]

    scheduler.start()

    XCTAssertEqual(results.events, expected)
}

Also

func testFormValidation() {
    UserSession.currenctScheduling.dateSignal.value = Date()
    UserSession.currenctScheduling.carSignal.value = Car()
    UserSession.currenctScheduling.servicesSignal.value = [Service(), Service()]

    let location = scheduler.createHotObservable([
        next(100, "TEST"),
        next(150, "TEST 2"),
        next(200, "TEST 3")
        ])

    location.subscribe(onNext: { (text) in
        print("LOCATION: \(text)")
        UserSession.currenctScheduling.locationSignal.value = text
    }).addDisposableTo(disposeBag)


    var results = [Bool]()
    viewModel.formIsValid.subscribe(onNext: { (value) in
        results.append(value)
    }).addDisposableTo(disposeBag)

    let expected = [true, true, true]

    scheduler.start()

    XCTAssertEqual(results, expected)
}

I've tried things like binding my formIsValid to a Variable and verifying its value at the end.

func testFormValidation() {
        UserSession.currenctScheduling.dateSignal.value = Date()
        UserSession.currenctScheduling.carSignal.value = Car()
        UserSession.currenctScheduling.locationSignal.value = "TESTE"
        UserSession.currenctScheduling.servicesSignal.value = [Service(), Service()]

        sleep(5)

        XCTAssertTrue(viewModel.formIsValid.value)
}

But I never get the expected result. I do get a true signal after all the tests fail and the code goes back to executing. Also when running the app the code executes as expecte I just need to catch it in the test. Any ideas?!

Aucun commentaire:

Enregistrer un commentaire