[英]Rx and async nunit test
我正在尝试为项目创建异步单元测试,但无法理解如何等待异步主题完成:
[Test]
public async void MicroTest()
{
var value = 2;
var first = new AsyncSubject<int>();
var second = new AsyncSubject<int>();
first.Subscribe(_ =>
{
value = _;
second.OnCompleted();
});
first.OnNext(1);
// how to wait for the second subject to complete?
Assert.AreEqual(value, 1);
}
此测试的同步版本运行良好:
[Test]
public void MicroTest()
{
var value = 2;
var first = new Subject<int>();
var second = new Subject<int>();
first.Subscribe(_ =>
{
value = _;
second.OnCompleted();
});
first.OnNext(1);
Assert.AreEqual(value, 1);
}
首先,值得指出AsyncSubject<T>
不是Subject<T>
的异步版本。 两者实际上都是自由线程*(见脚注)。
AsyncSubject
是Subject
一个特化,旨在用于建模异步完成并返回单个结果的操作。 它有两个值得注意的特点:
它在内部用于各种地方,包括在Task
和Task<T>
上定义的ToObservable()
扩展方法。
Recall AsyncSubject<T>
仅返回收到的最终结果。 它通过等待OnCompleted()来实现这一点,因此它知道最终结果是什么。 因为你不叫OnCompleted()
在first
测试是有缺陷的OnNext()
处理程序-将永远不会被调用-在你的订阅调用传递lambda函数。
此外,它是无效的不调用OnNext()
上的至少一次AsyncSubject<T>
所以当调用await second;
如果你还没有这样做,你将得到一个InvalidOperationException
。
如果你按如下方式编写测试,一切都很好:
[Test]
public async void MicroTest()
{
var value = 2;
var first = new AsyncSubject<int>();
var second = new AsyncSubject<int>();
first.Subscribe(_ =>
{
// won't be called until an OnCompleted() has
// been invoked on first
value = _;
// you must send *some* value to second
second.OnNext(_);
second.OnCompleted();
});
first.OnNext(1);
// you must do this for OnNext handler to be called
first.OnCompleted();
// how to wait for the second subject to complete
await second;
Assert.AreEqual(value, 1);
}
作为一般规则,我会避免编写可以永远等待的异步测试。 当它导致构建服务器上的资源耗尽时,这尤其令人讨厌。 使用某种超时,例如:
await second.Timeout(TimeSpan.FromSeconds(1));
无需处理异常,因为这足以使测试失败。
**我从COM词典中借用了这个术语。 从这个意义上讲,我的意思是,与大多数Rx框架组件一样,它们通常会在您调用其方法的任何线程上运行。 自由线程并不一定意味着完全线程安全。 特别是,与AsyncSubject<T>
, Subject<T>
不会保护您免受Rx语法冲突的影响,即对OnNext
进行重叠调用。 使用Subject.Synchronize
或Observable.Synchronize
进行此保护。*
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.