3

我有以下的方法,它負責調用我的服務類,以及將結果到另一個方法來保存他們在我的分貝:任務ToObservable錯誤處理

public IObservable<bool> SyncSessions() 
{ 
    var subject = new ReplaySubject<bool>(); 

    try 
    { 
     var query = new ByFilterQuery { SearchPeriodStartTime = DateTime.Now }; 
     var sessions = _sessionService.GetSessions(query).Result; 
     var saved = SaveSessions(sessions); 
     subject.OnNext(saved); 
     subject.OnCompleted(); 
    } 
    catch (Exception ex) 
    { 
     subject.OnError(ex); 
    } 

    return subject; 
} 

_sessionService.GetSessions將拋出一個HttpRequestException如果服務器返回一個500或類似的東西。我有一個單元測試嘲笑這種行爲,並希望測試我的方法優雅地處理錯誤。

有沒有更好的方式在Rx時尚中傳播錯誤?我試着做:

_sessionService.GetSessions(query).ToObservable().Select(SaveSessions); 

但是這拋出我的錯誤,而不是它被傳遞到調用方法中的錯誤處理操作。我還計劃將這種方法與其他幾種方法合併,並處理聯合莊園中的錯誤。

編輯:這是我如何訂閱可觀察

Exception error = null; 
_sessionManager 
    .SyncSessions() 
    .Subscribe(null, e => error = e); 

Assert.That(error, Is.Not.Null.After(500)); 

我傳遞空到第一個參數,因爲我真的不關心,在本次測試的情況下

回答

2

首先,對於您發佈的原始代碼,我建議使用AsyncSubject而不是ReplaySubject。將其視爲針對單一結果案例進行了優化。

現在對你的問題......

每當觀察到源產生的異常,該異常是通過OnError處理器傳播。如果您在訂閱observable時未提供OnError處理程序,則會拋出異常。

小的代碼,你貼:

_sessionService.GetSessions(query).ToObservable().Select(SaveSessions); 

是不夠的。如果沒有發佈顯示您如何訂閱observable的代碼,我只能猜測您沒有提供OnError處理程序。基於OP的測試代碼

編輯

是您的模擬服務返回Task拋出異常,或者是模擬服務只是拋出異常?除非你正在使用async/await,一個應該返回Task的函數,但在創建Task時會拋出異常,將立即引發異常,而不是返回失敗的Task。 ToObservable從未被調用,因爲GetSessions拋出。如果您更改模擬服務以返回失敗Task,那麼您的測試可能會正常工作。

如果您想要捕獲即時異常以及失敗的任務,那麼您可以使用Defer推遲執行您的方法,直到觀察者訂閱。它還將收集任何立即拋出的異常以及失敗的任務:

return Observable 
    .Defer(() => _sessionService.GetSessions(query)) 
    .Select(SaveSessions); 
+0

添加訂閱代碼 – JFoulkes

+0

測試發生錯誤。 GetSessions()調用了response.EnsureSuccessStatusCode();所以它可能會引發錯誤 – JFoulkes