不通过调度程序的 RxJS 测试 Observable 序列
RxJS Testing Observable sequence without passing scheduler
我在尝试测试类似于以下函数的一段代码时遇到问题。
问题基本上可以归结为:是否可以更改 debounce
运算符的调度程序而不将单独的 Scheduler
传递给函数调用?
下面的例子应该更具体地解释用例。我正在尝试测试类似于以下的一段代码。我想测试函数中的链(使用 TestScheduler),而不必将调度程序传递给 debounce()
运算符。
// Production code
function asyncFunctionToTest(subject) {
subject
.tap((v) => console.log(`Tapping: ${v}`))
.debounce(1000)
.subscribe((v) => {
// Here it would call ReactComponent.setState()
console.log(`onNext: ${v}`)
});
}
测试文件将包含以下代码来调用函数并确保主题发出值。
// Testfile
const testScheduler = new Rx.TestScheduler();
const subject = new Rx.Subject();
asyncFunctionToTest(subject);
testScheduler.schedule(200, () => subject.onNext('First'));
testScheduler.schedule(400, () => subject.onNext('Second'))
testScheduler.advanceTo(1000);
上面的测试代码仍然需要一秒钟的时间来进行去抖动。我找到的唯一解决方案是将 TestScheduler
传递给函数并将其传递给 debounce(1000, testScheduler)
方法。这将使去抖运算符使用测试调度程序。
我最初的想法是使用observeOn
或subscribeOn
通过更改
来更改整个操作链中使用的defaultScheduler
asyncFunctionToTest(subject);
类似于 asyncFunctionToTest(subject.observeOn(testScheduler));
或 asyncFunctionToTest(subject.subscribeOn(testScheduler));
这并没有给我预期的结果,但是我想我可能不完全理解 observeOn
和 subscribeOn
运算符的工作方式。 (我现在估计,当使用这些操作符时,它会改变整个操作链的调度程序运行,但操作符仍然选择他们自己的调度程序,除非特别通过?)
以下 JSBin 包含我在调度程序中传递的 运行nable 示例。 http://jsbin.com/kiciwiyowe/1/edit?js,console
不,不是真的,除非你真的修补了 RxJS 库。我知道这是最近作为 issue 提出的,并且可能支持说,能够在将来的某个时候更改 DefaultScheduler 的内容,但目前无法可靠地完成。
有什么理由不能包含调度程序吗?所有接受 Schedulers 的操作员都已经选择这样做并具有合理的默认值,所以它真的不需要任何成本,因为您的生产代码可以简单地忽略该参数。
为什么简单地添加 observeOn
或 subscribeOn
并不能解决问题,更一般地说,这两个运算符实际上只影响事件在 after[ 之后的传播方式=27=]他们已经被那个接线员收到了。
例如,您可以通过执行以下操作来实现 observeOn
:
Rx.Observable.prototype.observeOn = (scheduler) => {
var source = this;
return Rx.Observable.create((observer) => {
source.subscribe(x =>
{
//Reschedule this for a later propagation
scheduler.schedule(x,
(s, state) => observer.onNext(state));
},
//Errors get forwarded immediately
e => observer.onError(e),
//Delay completion
() => scheduler.schedule(null, () => observer.onCompleted()))
});
};
以上所做的只是重新安排传入的事件,如果下游或上游的操作员有其他延迟,则此操作员对其没有影响。 subscribeOn
具有类似的行为,只是它重新安排订阅而不是事件。
我在尝试测试类似于以下函数的一段代码时遇到问题。
问题基本上可以归结为:是否可以更改 debounce
运算符的调度程序而不将单独的 Scheduler
传递给函数调用?
下面的例子应该更具体地解释用例。我正在尝试测试类似于以下的一段代码。我想测试函数中的链(使用 TestScheduler),而不必将调度程序传递给 debounce()
运算符。
// Production code
function asyncFunctionToTest(subject) {
subject
.tap((v) => console.log(`Tapping: ${v}`))
.debounce(1000)
.subscribe((v) => {
// Here it would call ReactComponent.setState()
console.log(`onNext: ${v}`)
});
}
测试文件将包含以下代码来调用函数并确保主题发出值。
// Testfile
const testScheduler = new Rx.TestScheduler();
const subject = new Rx.Subject();
asyncFunctionToTest(subject);
testScheduler.schedule(200, () => subject.onNext('First'));
testScheduler.schedule(400, () => subject.onNext('Second'))
testScheduler.advanceTo(1000);
上面的测试代码仍然需要一秒钟的时间来进行去抖动。我找到的唯一解决方案是将 TestScheduler
传递给函数并将其传递给 debounce(1000, testScheduler)
方法。这将使去抖运算符使用测试调度程序。
我最初的想法是使用observeOn
或subscribeOn
通过更改
asyncFunctionToTest(subject);
类似于 asyncFunctionToTest(subject.observeOn(testScheduler));
或 asyncFunctionToTest(subject.subscribeOn(testScheduler));
这并没有给我预期的结果,但是我想我可能不完全理解 observeOn
和 subscribeOn
运算符的工作方式。 (我现在估计,当使用这些操作符时,它会改变整个操作链的调度程序运行,但操作符仍然选择他们自己的调度程序,除非特别通过?)
以下 JSBin 包含我在调度程序中传递的 运行nable 示例。 http://jsbin.com/kiciwiyowe/1/edit?js,console
不,不是真的,除非你真的修补了 RxJS 库。我知道这是最近作为 issue 提出的,并且可能支持说,能够在将来的某个时候更改 DefaultScheduler 的内容,但目前无法可靠地完成。
有什么理由不能包含调度程序吗?所有接受 Schedulers 的操作员都已经选择这样做并具有合理的默认值,所以它真的不需要任何成本,因为您的生产代码可以简单地忽略该参数。
为什么简单地添加 observeOn
或 subscribeOn
并不能解决问题,更一般地说,这两个运算符实际上只影响事件在 after[ 之后的传播方式=27=]他们已经被那个接线员收到了。
例如,您可以通过执行以下操作来实现 observeOn
:
Rx.Observable.prototype.observeOn = (scheduler) => {
var source = this;
return Rx.Observable.create((observer) => {
source.subscribe(x =>
{
//Reschedule this for a later propagation
scheduler.schedule(x,
(s, state) => observer.onNext(state));
},
//Errors get forwarded immediately
e => observer.onError(e),
//Delay completion
() => scheduler.schedule(null, () => observer.onCompleted()))
});
};
以上所做的只是重新安排传入的事件,如果下游或上游的操作员有其他延迟,则此操作员对其没有影响。 subscribeOn
具有类似的行为,只是它重新安排订阅而不是事件。