我使用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
进行断言将有希望使测试更具可读性。
顺便说一句,我认为有一个变量是非常好的。上面的代码很容易阅读,这是最重要的。 @ PL的答案很好,也很优雅,但是你必须努力去理解正在发生什么......也许把它变成一个扩展FailIfNothingHappened() – 2010-10-15 15:33:56
@Sergey Aldoukhov:我同意,但是PL的答案学会了我如何使用'物化'来推测我的IObservable行为。对于使用变量来捕捉发生的事情的更复杂的测试可能更难理解。另外,根据您的建议创建扩展可能会更容易理解正在发生的事情。 – 2010-10-15 16:01:32
我编辑了我的问题,使其更清楚我想要什么。 – 2010-10-29 11:59:03