RxTest - 如何将事件<Void>作为 Void 不相等



ViewModel有一个输入(观察者(,该输入(观察者(绑定到UIViewControllerUIButtontap事件。此观察器的类型为AnyObserver<Void>

在我的单元测试中,这就是我所期望的:

let correctValues: [Recorded<Event<Void>>] = Recorded.events(
.next(0, ()),
.completed(0)
)

我的测试观察者定义是:

private var voidEventsObserver: TestableObserver<Void>!
let scheduler = TestScheduler(initialClock: 0)
voidEventsObserver = scheduler.createObserver(Void.self)

断言语句:

XCTAssertEqual(voidEventsObserver.events, correctValues)

我收到以下错误:

表达式类型"(("不明确,没有更多上下文

在 Rx 中,Void事件是正常的,要正确测试 ViewModel,需要比较它们。.next(0, ()).completed(0)Void不是Equatable,让它Equatable是没有意义的。但是,我需要断言事件是.next还是.error.completed。我如何断言该部分?

Void一起工作有时会很痛苦。

尝试了您的示例,但由于Void不是名义类型或由于这些类型已经具有与Equatable冲突的一致性,因此无法为包含VoidResultEvent添加一些条件Equatable一致性。

一种方法是执行以下操作:

XCTAssertEqual(voidEventsObserver.events.count, correctValues.count)
for (actual, expected) in zip(voidEventsObserver.events, correctValues) {
XCTAssertEqual(actual.time, expected.time, "different times")
let equal: Bool
switch (actual.value, expected.value) {
case (.next, .next),
(.completed, .completed):
equal = true
default:
equal = false
}
XCTAssertTrue(equal, "different event")
}

现在这很丑陋,很难阅读。另一种方法是引入包装器:

struct VoidRecord: Equatable {
let record: Recorded<Event<Void>>
static func == (lhs: Self, rhs: Self) -> Bool {
guard lhs.record.time == rhs.record.time else { return false }
switch (lhs.record.value, rhs.record.value) {
case (.next, .next),
(.completed, .completed):
return true
default:
return false
}
}
}
XCTAssertEqual(
voidEventsObserver.events.map(VoidRecord.init),
correctValues.map(VoidRecord.init)
)

这读起来好多了。请注意,上述内容将.error事件视为始终不同。如果您需要比较错误事件,只需将此逻辑从 RxSwift 添加到上面的==函数中即可。

这是对我有用的解决方案。它将 Void 替换为事件等同的 Voidvalue。后来它使用 XCTAssertEqual,它是 RxSwift 库的一部分,因此行为和输出将是一致的。

func XCTAssertEqual(_ lhs: [Recorded<Event<Void>>], _ rhs: [Recorded<Event<Void>>], file: StaticString = #file, line: UInt = #line) {

struct VoidValue: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
return true
}
}

let toVoidValueEvent: (Event<Void>) -> Event<VoidValue> = { event in
switch event {
case .completed:
return .completed
case .error(let e1)
:
return .error(e1)
case .next:
return .next(.init())
}
}

let lhsRecords: [Recorded<Event<VoidValue>>] = lhs.map({ Recorded(time: $0.time, value: toVoidValueEvent($0.value)) })
let rhsRecords: [Recorded<Event<VoidValue>>] = rhs.map({ Recorded(time: $0.time, value: toVoidValueEvent($0.value)) })

XCTAssertEqual(lhsRecords, rhsRecords)
}

相关内容

最新更新