text: Q:
  
  Test PublishSubject for ViewState
  
  I'm trying to test the main functionality of my ViewModel. The important step is to test te loaded state completed. But for sure, for a better test it could be interesting to test al states.
  I was reading a lot of post and information about RxTest and RxBlocking but I'm not able to test this module. If someone can help me, it would be great!
  struct Product: Equatable { }
  struct Promotion { }
  
  protocol ProductsRepository {
      func fetchProducts() -> Observable<Products>
      func fetchPromotions()  -> Observable<[Promotion]>
  }
  
  struct ProductCellViewModel: Equatable {
      let product: Product
  }
  
  struct Products {
      let products: [Product]
  }
  
  enum ProductsViewState: Equatable {
      case loading
      case empty
      case error
      case loaded ([ProductCellViewModel])
  }
  
  class ProductsViewModel {
  
      var repository: ProductsRepository
  
      let disposeBag = DisposeBag()
      private var productCellViewModel: [ProductCellViewModel]
      private var promotions: [Promotion]
  
      // MARK: Input
  
      init(repository: ProductsRepository) {
          self.repository = repository
          productCellViewModel = [ProductCellViewModel]()
          promotions = [Promotion]()
      }
  
      func requestData(scheduler: SchedulerType) {
          state.onNext(.loading)
          resetCalculate()
          repository.fetchProducts()
              .observeOn(scheduler)
              .flatMap({ (products) -> Observable<[ProductCellViewModel]> in
                  return self.buildCellViewModels(data: products)
              }).subscribe(onNext: { (cellViewModels) in
                  self.productCellViewModel = cellViewModels
              }, onError: { (error) in
                  self.state.onNext(.error)
              }, onCompleted: {
                  self.repository.fetchPromotions()
                      .flatMap({ (promotions) -> Observable<[Promotion]> in
                          self.promotions = promotions
                          return Observable.just(promotions)
                      }).subscribe(onNext: { (_) in
                          self.state.onNext(.loaded(self.productCellViewModel))
                      }, onError: { (error) in
                          self.state.onNext(.error)
                      }).disposed(by: self.disposeBag)
              }).disposed(by: disposeBag)
      }
  
      // MARK: Output
  
      var state = PublishSubject<ProductsViewState>()
  
      // MARK: ViewModel Map Methods
  
      private func buildCellViewModels(data: Products) -> Observable <[ProductCellViewModel]> {
          var viewModels = [ProductCellViewModel]()
          for product in data.products {
              viewModels.append(ProductCellViewModel.init(product: product))
          }
          return Observable.just(viewModels)
      }
  
      func resetCalculate() {
          productCellViewModel = [ProductCellViewModel]()
      }
  }
  
  The goal is to be able to test all of ProductsViewState after viewmodel.requestData() is being called
  
  A:
  
  The key here is that you have to inject your scheduler into the function so you can inject a test scheduler. Then you will be able to test your state. BTW that state property should be a let not a var.
  class ProductsViewModelTests: XCTestCase {
  
      var scheduler: TestScheduler!
      var result: TestableObserver<ProductsViewState>!
      var disposeBag: DisposeBag!
  
      override func setUp() {
          super.setUp()
          scheduler = TestScheduler(initialClock: 0)
          result = scheduler.createObserver(ProductsViewState.self)
          disposeBag = DisposeBag()
      }
  
      func testStateLoaded() {
          let mockRepo = MockProductsRepository(products: { .empty() }, promotions: { .empty() })
          let viewModel = ProductsViewModel(repository: mockRepo)
  
          viewModel.state.bind(to: result).disposed(by: disposeBag)
          viewModel.requestData(scheduler: scheduler)
  
          scheduler.start()
  
          XCTAssertEqual(result.events, [.next(0, ProductsViewState.loading), .next(1, .loaded([]))])
      }
  
      func testState_ProductsError() {
          let mockRepo = MockProductsRepository(products: { .error(StubError()) }, promotions: { .empty() })
          let viewModel = ProductsViewModel(repository: mockRepo)
  
          viewModel.state.bind(to: result).disposed(by: disposeBag)
          viewModel.requestData(scheduler: scheduler)
  
          scheduler.start()
  
          XCTAssertEqual(result.events, [.next(0, ProductsViewState.loading), .next(1, .error)])
      }
  
      func testState_PromotionsError() {
          let mockRepo = MockProductsRepository(products: { .empty() }, promotions: { .error(StubError()) })
          let viewModel = ProductsViewModel(repository: mockRepo)
  
          viewModel.state.bind(to: result).disposed(by: disposeBag)
          viewModel.requestData(scheduler: scheduler)
  
          scheduler.start()
  
          XCTAssertEqual(result.events, [.next(0, ProductsViewState.loading), .next(1, .error)])
      }
  }
  
  struct StubError: Error { }
  
  struct MockProductsRepository: ProductsRepository {
      let products: () -> Observable<Products>
      let promotions: () -> Observable<[Promotion]>
  
      func fetchProducts() -> Observable<Products> {
          return products()
      }
  
      func fetchPromotions() -> Observable<[Promotion]> {
          return promotions()
      }
  }
  
  