我有以下方法负责调用我的服务类并将结果传递给另一个方法,以便将它们保存在我的数据库中:
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;
}
如果服务器返回500或类似的东西,_sessionService.GetSessions将抛出HttpRequestException。我有一个单元测试,它嘲笑这种行为,并希望测试我的方法优雅地处理错误。
有没有更好的方法以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));
我将null传递给第一个参数,因为在此测试的上下文中我并不关心它
答案 0 :(得分: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);