1

我们有三个状态。我们如何测试(使用单元测试)我们的类,它每 5 秒生成一次随机状态,并且不能连续两次生成相同的状态?我们的随机生成器类的代码如下 ` final class StateRandomGenerator: RandomGeneratorProtocol { private var sourceObservable: Disposable? private(set) var previousValue: Int? var generatedValue: PublishSubject = PublishSubject()

init(_ interval: RxTimeInterval,_ scheduler: SchedulerType = MainScheduler.instance) {
    sourceObservable = Observable<Int>
        .interval(interval, scheduler: scheduler)
        .flatMap { [unowned self] _ in self.generateRandom()}
        .compactMap { state in
            return state?.description
        }
        .subscribe(onNext: { [weak self] description in
            self?.generatedValue.onNext(description)
        })
}
func generateRandom() -> Observable<ConnectionState?> {
    return Observable.create { [weak self] observer  in
        var randomNumber = Int.random(in: 0..<ConnectionState.count)
        guard let previousValue = self?.previousValue else {
            let value = ConnectionState(rawValue: randomNumber)
            self?.previousValue = randomNumber
            observer.onNext(value)
            return Disposables.create()
        }
        while randomNumber == previousValue {
            randomNumber = Int.random(in: 0..<ConnectionState.count)
        }
        self?.previousValue = randomNumber
        let value = ConnectionState(rawValue: randomNumber)
        observer.onNext(value)
        
        return Disposables.create()
    }
}
enum ConnectionState: Int {
case error
case connecting
case established

var description: String {
    switch self {
    case .connecting:
        return "It is connecting"
    case .error:
        return "There is an error"
    case .established:
        return "Thе connection is established"
    }
}

} `

4

1 回答 1

0

您无法成功对您的课程进行单元测试,因为它不会停止。它只是固定 CPU 并咀嚼内存,直到系统最终饿死并崩溃。

下面是一个工作且经过测试的 Observable,它可以满足您的需求...该测试创建 100,000 个 ConnectionState,然后检查以确保没有两个相邻的相同。

该函数的主要逻辑是传递给它的闭包,map它抓取所有案例并过滤掉前一个案例。从余数中选择一个随机元素。

在我期望的任何枚举中都可以很容易地使其通用。我将把它作为练习留给读者。

func stateRandom(_ interval: RxTimeInterval,_ scheduler: SchedulerType = MainScheduler.instance) -> Observable<ConnectionState> {
    let previous = BehaviorRelay<ConnectionState?>(value: nil)
    return Observable<Int>.interval(interval, scheduler: scheduler)
        .withLatestFrom(previous)
        .map { ConnectionState.allExcept($0) }
        .flatMap { Observable.just($0.randomElement()!) }
        .do(onNext: { previous.accept($0) })
}

extension CaseIterable where Self: Equatable {
    static func allExcept(_ value: Self?) -> [Self] {
        allCases.filter { $0 != value }
    }
}

enum ConnectionState: CaseIterable, Equatable {
    case error
    case connecting
    case established
}

class Tests: XCTestCase {

    func test() throws {
        let scheduler = TestScheduler(initialClock: 0)

        let result = scheduler.start { stateRandom(.seconds(1), scheduler).take(100000) }

        for (prev, current) in zip(result.events, result.events.dropFirst()) {
            XCTAssertNotEqual(prev.value, current.value)
        }
    }
}
于 2021-06-08T02:05:51.680 回答