我正在尝试为项目创建异步单元测试,但无法理解如何等待异步主题完成:
[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 与 Subject
首先,值得指出的是 AsyncSubject<T>
不是 Subject<T>
的异步版本.两者实际上都是自由线程*(见脚注)。
AsyncSubject
是 Subject
的特化旨在用于模拟异步完成并返回单个结果的操作。它有两个值得注意的特点:
- 只发布最后一个结果
- 结果被缓存,并在完成后可供订阅的观察者使用。
它在内部的各个地方使用,包括 ToObservable()
Task
上定义的扩展方法和 Task<T>
.
测试的问题
召回AsyncSubject<T>
只会返回收到的最终结果。它通过等待 OnCompleted() 来完成此操作,因此它知道最终结果是什么。因为你不叫OnCompleted()
在 first
你的测试有缺陷,因为 OnNext()
处理程序 - 在您的 Subscribe 调用中传递的 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));
不需要处理异常,因为这足以让测试失败。
**我从the COM lexicon借用了这个词.在这个意义上,我的意思是,与大多数 Rx 框架组件一样,它们通常会在您碰巧调用它们的方法的任何线程上运行。自由线程并不一定意味着完全线程安全。特别是,不像 AsyncSubject<T>
, Subject<T>
不会保护您免受对 OnNext
的重叠调用的 Rx 语法违规.使用 Subject.Synchronize
或 Observable.Synchronize
为了这种保护。*
关于c# - Rx 和异步 nunit 测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22634195/