为什么 Observable.Do 会抛出 InvalidOperationException“序列不包含元素”

问题描述 投票:0回答:1

我确实在下面的代码中遇到了(恕我直言)意外的异常

InvalidOperationException
“序列不包含元素”,我认为情况不应该如此。请参阅下面的代码、背景信息和说明。

问题

为了轻松重现并演示它,使用我的 SUT

Effect
的单元测试中的代码被注释掉,并替换为给定的代码,这应该清楚地表明我正在尝试做什么以及我是什么正在尝试测试。

因此,我可以将问题简化为“当它是一个完全有效的用例时,为什么在执行

Observable.Do
时会出现“序列不包含元素”异常”:

IObservable<int> observable = Observable.Empty<int>();

而且,我想测试这个,一个完成的空序列。

单元测试

public class EffectTests {

    [Fact]
    public async void TestEmpty() {
        // IObservable<int> observable = Effect<Unit, int>.Empty.Invoke()
        //     .Delay(System.TimeSpan.FromSeconds(1.2));

        IObservable<int> observable = Observable.Empty<int>()
            .Delay(System.TimeSpan.FromSeconds(1.2));

        // Exception has occurred: CLR/System.InvalidOperationException
        // Exception thrown: 'System.InvalidOperationException' in System.Reactive.dll: 'Sequence contains no elements.'
        //    at System.Reactive.Subjects.AsyncSubject`1.GetResult()
        //    at EffectTests.<TestEmpty>d__0.MoveNext() in 
        await observable.Do(
            onNext: _ => AssertEx.Fail()
        );
    }
}

public static class AssertEx {
    public static void Fail(string message = "")
        => throw new Xunit.Sdk.XunitException(message);
}

背景

我希望注释中的代码和 xUnit 测试设置能够显示我正在尝试做的事情:

我有一个自定义结构体

Effect
,它基本上存储一个返回
IObservable<T>
的函数。这应该已经表明了一个事实,即 Effect 实际上可以返回任何类型的可观察值(通过函数
Invoke()
)。该可观察对象现在可能返回将同步或异步发出的值,它可能立即失败或成功,或者它可能发出一个或多个值,或者根本不发出。

在我的单元测试中,在

Effect.Empty
的情况下,Observable 实际上是一个空序列,因此它不会发出任何值。因此,当回调
Assert.Fail()
被调用时,我精确地添加了
onNext

附加信息

所以,

Observable.Do
的文档说:

    // Summary:
    //     Invokes an action for each element in the observable sequence, and propagates
    //     all observer messages through the result sequence. This method can be used for
    //     debugging, logging, etc. of query behavior by intercepting the message stream
    //     to run arbitrary actions for messages on the pipeline.

它显然没有说明如果序列为空就会抛出异常。它还清楚地说明了用例,用于“调试、日志记录等”,所以我认为这非常适合我的用例,即单元测试。

我的问题

  1. 为什么
    Observable.Do
    会抛出异常?
  2. 如何缓解单元测试中的问题?

SO 上已经有很多关于“序列不包含元素”的问题,但据我所知,没有人具体提及

Observable.Do
。但任何现有的答案也值得赞赏。

c# observable xunit reactivex
1个回答
0
投票

解决方案:

您可以使用

.DefaultIfEmpty()
来避免等待空观察者。 对于你的情况:

[Fact]
public async void TestEmpty() {
    // IObservable<int> observable = Effect<Unit, int>.Empty.Invoke()
    //     .Delay(System.TimeSpan.FromSeconds(1.2));

    IObservable<int> observable = Observable.Empty<int>()
        .Delay(System.TimeSpan.FromSeconds(1.2));

    // Exception has occurred: CLR/System.InvalidOperationException
    // Exception thrown: 'System.InvalidOperationException' in System.Reactive.dll: 'Sequence contains no elements.'
    //    at System.Reactive.Subjects.AsyncSubject`1.GetResult()
    //    at EffectTests.<TestEmpty>d__0.MoveNext() in 
    await observable.Do(
        onNext: _ => AssertEx.Fail()
    ).DefaultIfEmpty();
}

更多信息:

问题不在于

Observable.Do
,而在于最终等待空观察者的测试。

和你一样,我没有找到任何文档来说明为什么它会这样。

© www.soinside.com 2019 - 2024. All rights reserved.