gpt4 book ai didi

mvvm - 测试 ViewState 的 PublishSubject

转载 作者:行者123 更新时间:2023-12-03 10:25:36 24 4
gpt4 key购买 nike

我正在尝试测试我的 ViewModel 的主要功能。重要的步骤是测试加载状态完成。但可以肯定的是,为了更好的测试,测试所有状态可能会很有趣。

我正在阅读很多关于 RxTest 和 RxBlocking 的帖子和信息,但我无法测试这个模块。如果有人可以帮助我,那就太好了!

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]()
}
}

目标是能够在调用 viewmodel.requestData() 之后测试所有 ProductsViewState

最佳答案

这里的关键是你必须将你的调度器注入(inject)到函数中,这样你才能注入(inject)一个测试调度器。然后你就可以测试你的 state .顺便说一句,state属性应该是 let 而不是 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()
}
}

关于mvvm - 测试 ViewState 的 PublishSubject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56425073/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com