我想从消费者的角度测试可观察对象的行为。
当我订阅(冷)或不订阅(热)时,我无法确定是否会有副作用。
有没有办法可以在单元测试中验证此行为?
我从rxjs / test中获得了TestScheduler
的信息,但是我没有看到一种很好的方法来验证可观察对象的创建次数。
// ...the create method has been mocked to emit after 3 frames
const create$ = api.create(potato).pipe(
tap(console.log.bind(null, 'object created'))
);
create$.subscribe();
create$.subscribe();
create$.subscribe();
// Test how many times create$ has gotten a subscription, generated a cold observable, and completed.
const timing = '---(a|)'; // wait 3 frames, emit value of `a`, complete
const values = { a: potato };
expectObservable(create$).toBe(timing, values);
此测试通过,但是“创建对象”消息触发了四次(我的订阅发出3次,中间件发出一次)。
我想写一个失败的测试(真否定),然后再更改可观察对象的行为以使其符合api.create
的要求。
如何验证创建行为仅执行一次?
我尝试过:
spyOn
,但是实际的create方法仅被调用一次。Array.isArray(create$.observers)
-太间接了,只检查它是否很热,而不是它的行为是否符合预期。tap(() => runCount++)
\ expect(runCount).toBe(1)
-如果我刷新调度程序,则可以使用,但是似乎超出了rxjs测试的标准。Observable.create
和工厂功能来手动跟踪运行计数。也可以,有点冗长。答案 0 :(得分:0)
我不确定我是否遵循您的要求,但是我可以解决您对创建可观察项的次数的担忧:
一次。
const create$ = api.create(potato)
这将创建可观察的对象。从可观测对象到订阅者的.pipe
附件是可观测对象的数据路径的一部分。
potato ---(pipe)--->.subscribe()
+----(pipe)--->.subscribe()
+----(pipe)--->.subscribe()
+----(pipe)--->(expectObservable inspection)
相反,您似乎可能希望在其中添加一条额外的管道来共享结果。也许并不奇怪,该管道称为share
。
输入
import { Observable, Subject } from 'rxjs';
import { share, tap } from 'rxjs/operators';
let obj: Subject<string> = new Subject<string>();
let obs: Observable<string> = obj.pipe(tap(() => console.log('tap pipe')));
obs.subscribe((text) => console.log(`regular: ${text}`));
obs.subscribe((text) => console.log(`regular: ${text}`));
obs.subscribe((text) => console.log(`regular: ${text}`));
let shared: Observable<string> = obs.pipe(share());
shared.subscribe((text) => console.log(`shared: ${text}`));
shared.subscribe((text) => console.log(`shared: ${text}`));
shared.subscribe((text) => console.log(`shared: ${text}`));
obj.next('Hello, world!');
输出
tap pipe
regular: Hello, world!
tap pipe
regular: Hello, world!
tap pipe
regular: Hello, world!
tap pipe
shared: Hello, world!
shared: Hello, world!
shared: Hello, world!
答案 1 :(得分:0)
到目前为止,这是我迄今为止发现的最佳方法,可以在单元测试中对每个订阅仅一次调用一次内部可观察性。
spyOn
从“执行真实工作”函数中返回该值scheduler.run(rx => {
let runCount = 0;
const timing = '---(a|)';
const values = { a: {x:42} };
// This represents the inner cold observable.
// We want to validate that it does/does not get called once per subscription
const mockedCreate$ = rx.cold(timing, values).pipe(
tap(() => runCount++),
);
spyOn(api, 'doCreate').and.returnValue(mockedCreate$);
const create$ = api.create({x:42}); // internally, calls doCreate
create$.subscribe();
create$.subscribe();
create$.subscribe();
// Explanation:
// If api.create wasn't multicasting/sharing the result of the doCreate
// operation, we'd see multiple actual save operations, not just 1
rx.expectObservable(create$).toBe(timing, values);
scheduler.flush();
expect(runCount).toBe(1, 'how often the "real" create operation ran');
});