使用响应式扩展对事件进行单元测试 [英] Unit testing for an event using Reactive Extensions
问题描述
我正在使用 .NET(Rx)的反应扩展将事件显示为 IObservable< T>
.我想创建一个单元测试,在其中断言某个特定事件已被触发.这是我要测试的类的简化版本:
I'm using Reactive Extensions for .NET (Rx) to expose events as IObservable<T>
. I want to create an unit test where I assert that a particular event is fired. Here is a simplified version of the class I want to test:
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
使得测试变得更加容易.
Obviously my real classes are more complex. My goal is to verify that performing some actions with the class under test leads to a sequence of events signaled on the IObservable
. Luckily the classes I want to test implement IDisposable
and calling OnCompleted
on the subject when the object is disposed makes it much easier to test.
这是我的测试方式:
// Arrange
var classUnderTest = new ClassUnderTest();
var eventFired = false;
classUnderTest.SomethingHappened.Subscribe(_ => eventFired = true);
// Act
classUnderTest.DoSomething();
// Assert
Assert.IsTrue(eventFired);
使用变量来确定是否触发了一个事件并不太坏,但是在更复杂的情况下,我可能要验证是否触发了特定的事件序列.如果不简单地将事件记录在变量中,然后对变量进行断言,是否有可能?能够使用流畅的类似LINQ的语法对 IObservable
进行断言,有望使测试更具可读性.
Using a variable to determine if an event is fired isn't too bad, but in more complex scenarios I may want to verify that a particular sequence of events are fired. Is that possible without simply recording the events in variables and then doing assertions on the variables? Being able to use a fluent LINQ-like syntax to make assertions on an IObservable
would hopefully make the test more readable.
推荐答案
此答案已更新为现在发布的Rx 1.0版.
This answer has been updated to the now released version 1.0 of Rx.
官方文档仍然很少,但是测试和调试可观察序列在MSDN上a>是一个很好的起点.
Official documentation is still scant but Testing and Debugging Observable Sequences on MSDN is a good starting place.
测试类应从 < Microsoft.Reactive.Testing
名称空间中的code> ReactiveTest .该测试基于 TestScheduler
为测试提供虚拟时间.
The test class should derive from ReactiveTest
in the Microsoft.Reactive.Testing
namespace. The test is based around a TestScheduler
that provides virtual time for the test.
TestScheduler.Schedule
方法可用于将活动在虚拟时间的某些点(滴答声)排队.该测试由 TestScheduler.Start
执行.这将返回一个 ITestableObserver< T>
,例如,可以通过使用 ReactiveAssert
类将其用于断言.
The TestScheduler.Schedule
method can be used to queue up activities at certain points (ticks) in virtual time. The test is executed by TestScheduler.Start
. This will return an ITestableObserver<T>
that can be used for asserting for instance by using the ReactiveAssert
class.
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.Schedule
is used to schedule a call to DoSomething
at time 20 (measured in ticks).
然后 TestScheduler.Start
用于对可观察的 SomethingHappened
进行实际测试.订阅的生存期由调用的参数控制(再次以滴答表示).
Then TestScheduler.Start
is used to perform the actual test on the observable SomethingHappened
. The lifetime of the subscription is controlled by the arguments to the call (again measured in ticks).
最后, ReactiveAssert.AreElementsEqual
用于验证是否按预期在时间20调用了 OnNext
.
Finally ReactiveAssert.AreElementsEqual
is used to verify that OnNext
was called at time 20 as expected.
该测试验证调用 DoSomething
会立即触发可观察到的 SomethingHappened
.
The test verifies that calling DoSomething
immediately fires the observable SomethingHappened
.
这篇关于使用响应式扩展对事件进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!