BETA

RxSwiftでエラー検知

投稿日:2018-12-22
最終更新:2018-12-22

RxSwift 学習中です

備忘録も兼ねて。

実装例 : サインイン実行


protocol ServerAPIWrapper {  
    func signIn(accountName: String, password: String) -> ServerAPIWrapperError?  
}  

enum SignInError: Error {  
    case noIdInput  
    case noPasswordInput  
}  
protocol SignIn {  
    func signIn(asccountName: String, password: String) -> Observable<Void>  
}  
class SignInImpl: SignIn {  
    private let serverAPIWrapper: ServerAPIWrapper!  
    private let scheduler = SerialDispatchQueueScheduler(qos: .default)  

    init(serverAPIWrapper: ServerAPIWrapper) {  
        self.serverAPIWrapper = serverAPIWrapper  
    }  

    func signIn(asccountName: String, password: String) -> Observable<Void> {  
        guard !asccountName.isEmpty else {  
            return Observable<Void>.error(SignInError.noIdInput)  
        }  

        guard !password.isEmpty else {  
            return Observable<Void>.error(SignInError.noPasswordInput)  
        }  

        let observable = Observable<Void>.create { (observer) -> Disposable in  
            let result = self.serverAPIWrapper.signIn(accountName: asccountName,  
                                                      password: password)  
            if result != nil {  
                observer.onError(result)  
            }  
            else {  
                observer.onCompleted()  
            }  
            return Disposables.create()  
        }  

        return observable.observeOn(scheduler)  
    }  
}  

テスト(Quick & Nimbleを使用)

var signIn: SignIn!  
var mockServerWrapper: MockServerAPIWrapper!  
var bag: DisposeBag!  
beforeEach {  
    mockServerWrapper = MockServerAPIWrapper()  
    signIn = SignInImpl(serverAPIWrapper: mockServerWrapper)  
    bag = DisposeBag()  
}  
context("成功すると") {  
    var result: MaterializedSequenceResult<Void>!  
    beforeEach {  
        let observable = signIn.signIn(asccountName: "account", password: "test")  
        result = observable.toBlocking().materialize()  
    }  
    it("errorは呼ばれない") {  
        switch result! {  
        case .completed(_):  
            break  
        case .failed(_, _):  
            fail("not called failed")  
        }  
    }  
}  
context("asccountNameが未入力だと") {  
    var result: MaterializedSequenceResult<Void>!  
    beforeEach {  
        let observable = signIn.signIn(asccountName: "", password: "test")  
        result = observable.toBlocking().materialize()  
    }  
    it("noIdInputエラー") {  
    switch result! {  
    case .completed(_):  
        fail("not called completed")  
    case .failed(_, let error):  
        let signInError = error as! SignInError  
        expect(signInError).to(equal(.noIdInput))  
    }  
}  

記事に残そうと思った経緯

今まではHotなObservableを使っていたため、なんとなくonErrorを避ける傾向にありました。
この処理も最初は、Observable<SignInError?> をreturnし、onNextの中で正常とエラーを扱うようなクラスにしていました。
しかし、まだ理解が浅いながらも、「エラーを返す機構があるのだから、エラー処理はそちらでやるのが自然では?」と思い、勉強も兼ねてonErrorでエラーを処理するように変更しました。
慣れていないため少々苦戦したので、次の私が見返すために残しておきます。

おわりに

Rxはいいぞ!!!

技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
駆け出しエンジニアからエキスパートまで全ての方々のアウトプットを歓迎しております!
or 外部アカウントで 登録 / ログイン する
クランチについてもっと詳しく

この記事が掲載されているブログ

日々のつまづきや失敗、発見を記録して生きたいのでござるよ。

よく一緒に読まれる記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる
技術ブログをはじめよう Qrunch(クランチ)は、プログラマの技術アプトプットに特化したブログサービスです
or 外部アカウントではじめる
10秒で技術ブログが作れます!