【发布时间】:2015-08-13 09:01:07
【问题描述】:
我在测试使用Observable.FromAsync<T>() 和Observable.Switch<T>() 的类时遇到了麻烦。它所做的是等待一个可观察的触发器产生一个值,然后它开始一个异步操作,最后在一个输出序列中重新收集所有操作的结果。它的要点是这样的:
var outputStream = triggerStream
.Select(_ => Observable
.FromAsync(token => taskProducer.DoSomethingAsync(token)))
.Switch();
我用最少的部分进行了一些健全性检查测试,以了解发生了什么,这是 cmets 中的测试结果:
class test_with_rx : nspec
{
void Given_async_task_and_switch()
{
Subject<Unit> triggerStream = null;
TaskCompletionSource<long> taskDriver = null;
ITestableObserver<long> testObserver = null;
IDisposable subscription = null;
before = () =>
{
TestScheduler scheduler = new TestScheduler();
testObserver = scheduler.CreateObserver<long>();
triggerStream = new Subject<Unit>();
taskDriver = new TaskCompletionSource<long>();
// build stream under test
IObservable<long> streamUnderTest = triggerStream
.Select(_ => Observable
.FromAsync(token => taskDriver.Task))
.Switch();
/* Also tried with this Switch() overload
IObservable<long> streamUnderTest = triggerStream
.Select(_ => taskDriver.Task)
.Switch(); */
subscription = streamUnderTest.Subscribe(testObserver);
};
context["Before trigger"] = () =>
{
it["Should not notify"] = () => testObserver.Messages.Count.Should().Be(0);
// PASSED
};
context["After trigger"] = () =>
{
before = () => triggerStream.OnNext(Unit.Default);
context["When task completes"] = () =>
{
long result = -1;
before = () =>
{
taskDriver.SetResult(result);
//taskDriver.Task.Wait(); // tried with this too
};
it["Should notify once"] = () => testObserver.Messages.Count.Should().Be(1);
// FAILED: expected 1, actual 0
it["Should notify task result"] = () => testObserver.Messages[0].Value.Value.Should().Be(result);
// FAILED: of course, index out of bound
};
};
after = () =>
{
taskDriver.TrySetCanceled();
taskDriver.Task.Dispose();
subscription.Dispose();
};
}
}
在我也用模拟完成的其他测试中,我可以看到传递给 FromAsync 的 Func 实际上被调用了(例如taskProducer.DoSomethingAsync(token)),但是看起来没有更多的后续,并且输出流不会产生价值。
我还尝试在达到预期之前插入一些 Task.Delay(x).Wait() 或一些 taskDriver.Task.Wait(),但没有成功。
我阅读了this SO thread 并且知道调度程序,但乍一看我以为我不需要它们,没有使用ObserveOn()。我错了吗?我错过了什么?助教
为了完整性,测试框架是 NSpec,断言库是 FluentAssertions。
【问题讨论】:
-
阅读 Paul Betts 的答案(例如 here),可能在测试期间
FromAsync或Switch()在后台使用 MSTest.exe 提供的相同空闲调度程序/调度程序 ...
标签: c# unit-testing system.reactive