A ViewModel has an input (an observer) which is bound to tap
event of UIButton
in UIViewController
. This observer is of type AnyObserver<Void>
.
In my unit test, this is what I'm expecting:
let correctValues: [Recorded<Event<Void>>] = Recorded.events(
.next(0, ()),
.completed(0)
)
My test observer definition is:
private var voidEventsObserver: TestableObserver<Void>!
let scheduler = TestScheduler(initialClock: 0)
voidEventsObserver = scheduler.createObserver(Void.self)
Assert statement:
XCTAssertEqual(voidEventsObserver.events, correctValues)
I'm getting following error:
Expression type '()' is ambiguous without more context
In Rx, Void
events are normal and to properly test ViewModel, one needs to compare them. e.g. .next(0, ())
, .completed(0)
etc. Void
is not Equatable
and it doesn't make sense to make it Equatable
. However, I need to assert if the event is .next
or .error
or .completed
. How do I assert that part?
Working with Void
can be a pain at times.
Played around with your example, but adding some conditional conformance to Equatable
for Result
or Event
that contain Void
is not possible due to Void
not being a nominal type or due to these types already having a conflicting conformance to Equatable
.
One approach would be to do something like this:
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")
}
Now that's ugly as hell and hard to read. The other approach is to introduce a wrapper:
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)
)
That reads a lot nicer. Note that the above treats .error
events as always being different. If you need to compare error events, simply add this logic from RxSwift to the ==
function above.