RxTest - 如何比较 Event<Void> 因为 Void 不是 Equatable

RxTest - How to compare Event<Void> as Void is not Equatable

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)

我收到以下错误:

Expression type '()' is ambiguous without more context

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

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

试过你的例子,但是由于 Void 不是标称类型或由于这些类型已经与 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 中的 this logic 添加到上面的 == 函数即可。