az4dan
az4dan

Reputation: 659

Testing BehaviorSubject/Relay in RxSwift

I'm having trouble testing a BehaviorRelay. The following minimal code binds an observable to a BehaviorRelay, but when testing, the tests won't end and are hung - the observable keeps emitting events, because it starts with Observable.timer. When getting rid of the bindRx method and testing the observable only, it works without a problem. But I'd like to test the class properly - does that make sense?

How do I go about making this work?

import XCTest
import RxSwift
import RxCocoa

struct TestObject: Codable {
    var a: Int?
    var b: Int?

    private enum CodingKeys: String, CodingKey {
        case a = "test"
        case b
    }
}

extension TestObject: Equatable {
    static func == (lhs: TestObject, rhs: TestObject) -> Bool {
        return lhs.a == rhs.a && lhs.b == rhs.b
    }
}

class TestObjectFetcher {
    private let scheduler: SchedulerType
    private let disposeBag = DisposeBag()
    let testObject = BehaviorRelay<TestObject?>(value: nil)
    var syncInterval = 30.0

    init(scheduler: SchedulerType) {
        self.scheduler = scheduler
        self.bindRx()
    }

    var fetchTestObjectObservable: Observable<TestObject?> {
        return Observable<Int>.timer(0, period: self.syncInterval, scheduler: self.scheduler)
            .map { _ -> TestObject? in
                TestObject(a: 1, b: 2)
            }
    }

    private func bindRx() {
        self.fetchTestObjectObservable
            .bind(to: self.testObject)
            .disposed(by: self.disposeBag)
    }
}

class TestObjectFetcherTests: XCTestCase {
    let testScheduler = TestScheduler(initialClock: 0)
    func testTestObjectFetcher() {

        let testObjectFetcher = TestObjectFetcher(scheduler: testScheduler)

        let events: [Recorded<Event<TestObject?>>] = [
            Recorded.next(1, TestObject(a: 1, b: 2)),
            Recorded.next(31, TestObject(a: 1, b: 2)),
            Recorded.next(61, TestObject(a: 1, b: 2))
        ]

        let res = testScheduler.start(created: 0, subscribed: 0, disposed: 90) { () -> Observable<TestObject?> in
            return testObjectFetcher.testObject.asObservable()
        }

        XCTAssertEqual(res.events, events)
    }
}

Upvotes: 0

Views: 1220

Answers (1)

az4dan
az4dan

Reputation: 659

The problem was that the observable never completed. Adding scheduler.subscribeAt(100) {} and setting the fetcher to nil solved the problem.

Upvotes: 0

Related Questions