Alex
Alex

Reputation: 145

RxSwift PublishSubject unit test

Here's my view model

import Foundation
import RxSwift

class CitiesViewModel {
    let service: CityServiceProvider
    var cities: PublishSubject<[CityDetail]> = PublishSubject()
    let errorMessage: PublishSubject<String> = PublishSubject()
    
    init(service: CityServiceProvider) {
        self.service = service
    }
    
    func getCities(completion: (() -> ())? = nil)  {
        service.getCities { result in
            switch result {
            case .success(let response):
                self.cities.onNext(response.cityList)
            case .failure(let error):
                self.errorMessage.onNext(error.localizedDescription)
            }
            completion?()
        }
    }
}

I just wanted to know how can I test cities has value and errorMessage doesn't after the getCities() is called (I'll use a mock service in the unit test)

and here is my unit test

    func testSuccessfulResult() {
        let expectation = self.expectation(description: #function)
        let service = MockCityServiceWithSuccessResponse()
        let viewModel = CitiesViewModel(service: service)

        viewModel.getCities(completion: {
            expectation.fulfill()
        })
        
        viewModel.cities.subscribe { details in
            // This body will never execute
            guard let details = details.element else {
                XCTFail("Details is empty")
                return
            }
            XCTAssertTrue(details.count > 0, "Load details successfully")
        }.disposed(by: DisposeBag())
        
        wait(for: [expectation], timeout: 2)
    }

Upvotes: 1

Views: 275

Answers (1)

Daniel T.
Daniel T.

Reputation: 33979

You are subscribing to cities after the value has been emitted and the expectation fulfilled. Move your subscription to before the getCities call and you should see a success.

Also:

  • cities should not be a var. All Subjects should always be let constants.
  • your view model should not be exposing Subjects. Make the subjects private and expose an Observable instead. (Otherwise, anybody can push values into the subjects.)

Upvotes: 0

Related Questions