RxExpect is a testing framework for RxSwift.
Provide inputs then test outputs. This is an example code that tests map()
operator multiplying the values by 2.
func testMultiply() {
let test = RxExpect()
let value = PublishSubject<Int>()
let result = value.map { $0 * 2 }
// provide inputs
test.input(value, [
next(100, 1),
next(200, 2),
next(300, 3),
completed(400)
])
// test output
test.assert(result) { events in
XCTAssertEqual(events, [
next(100, 2),
next(200, 4),
next(300, 6),
completed(400)
])
}
}
It would be easy to understand if you imagine the marble diagram.
time --100-200-300-400 // virtual timeline
value --1---2---3---| // provide inputs
result --2---4---6---| // test these values
This is more complicated example.
final class ArticleDetailViewModelTests: XCTestCase {
func testLikeButtonSelected() {
let test = RxExpect()
let viewModel = ArticleDetailViewModel()
test.retain(viewModel) // IMPORTANT: prevent from being disposed while testing
// providing an user input: user tapped like button
test.input(viewModel.likeButtonDidTap, [
next(100, Void()),
])
// test output: like button become selected
test.assert(viewModel.isLikeButtonSelected) { events in
XCTAssertEqual(events.at(100...).elements, [true])
}
}
func testLikeButtonUnselected() {
let test = RxExpect()
let viewModel = ArticleDetailViewModel()
test.retain(viewModel) // IMPORTANT: prevent from being disposed while testing
// providing an user input: user tapped like button
test.input(viewModel.likeButtonDidTap, [
next(100, Void()),
])
// test output: like button become selected
test.assert(viewModel.isLikeButtonSelected) { events in
XCTAssertEqual(events.at(100...).elements, [false])
}
}
}
input(observer, events)
input(variable, events)
assert(source, closure)
-
For iOS 8+ projects with CocoaPods:
pod 'RxExpect'
-
For iOS 8+ projects with Carthage:
github "devxoul/RxExpect"
$ swift package generate-xcodeproj
$ open RxExpect.xcodeproj
RxExpect is under MIT license. See the LICENSE file for more info.