c# – 使用Reactive Extensions对事件进行单元测试

我正在使用 Reactive Extensions for .NET (Rx)将事件公开为IObservable< T>.我想创建一个单元测试,我断言特定事件被触发.这是我要测试的类的简化版本:
public sealed class ClassUnderTest : Idisposable {

  Subject<Unit> subject = new Subject<Unit>();

  public IObservable<Unit> SomethingHappened {
    get { return this.subject.AsObservable(); }
  }

  public void DoSomething() {
    this.subject.OnNext(new Unit());
  }

  public void dispose() {
    this.subject.OnCompleted();
  }

}

显然我的真正课程更复杂.我的目标是验证对被测试类执行某些操作会导致在IObservable上发出一系列事件.幸运的是,我想要测试的类实现Idisposable并在处理对象时调用OnCompleted使得测试更加容易.

这是我测试的方式:

// Arrange
var classUnderTest = new ClassUndertest();
var eventFired = false;
classUnderTest.somethingHappened.Subscribe(_ => eventFired = true);

// Act
classUnderTest.DoSomething();

// Assert
Assert.IsTrue(eventFired);

使用变量来确定事件是否被触发也不是太糟糕,但在更复杂的场景中,我可能想要验证是否触发了特定的事件序列.如果不简单地在变量中记录事件然后对变量进行断言,这是否可能?能够使用流畅的类LINQ语法在IObservable上进行断言有望使测试更具可读性.

解决方法

此答案已更新至现已发布的Rx版本1.0.

官方文档仍然很少,但MSDN上的Testing and Debugging Observable Sequences一个很好的起点.

测试类应该从Microsoft.Reactive.Testing命名空间中的ReactiveTest派生.该测试基于TestScheduler,为测试提供虚拟时间.

TestScheduler.Schedule方法可用于在虚拟时间内在某些点(滴答)排队活动.测试由TestScheduler.Start执行.这将返回ITestableObserver< T>例如,可以使用ReactiveAssert类来断言.

public class Fixture : ReactiveTest {

  public void SomethingHappenedtest() {
    // Arrange 
    var scheduler = new TestScheduler();
    var classUnderTest = new ClassUndertest();

    // Act 
    scheduler.Schedule(TimeSpan.FromTicks(20),() => classUnderTest.DoSomething());
    var actual = scheduler.Start(
      () => classUnderTest.somethingHappened,created: 0,subscribed: 10,disposed: 100
    );

    // Assert
    var expected = new[] { OnNext(20,new Unit()) };
    ReactiveAssert.AreElementsEqual(expected,actual.Messages);
  }

}

TestScheduler.Schedule用于在时间20安排对DoSomething的调用(以滴答为单位).

然后TestScheduler.Start用于对可观察的SomethingHappened执行实际测试.订阅的生命周期由调用的参数控制(再次以刻度形式测量).

最后,ReactiveAssert.AreElementsEqual用于验证OnNext是否按预期在时间20调用.

测试验证调用DoSomething会立即触发可观察的SomethingHappened.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...