笑话:模拟 RxJs 管道

Posted

技术标签:

【中文标题】笑话:模拟 RxJs 管道【英文标题】:Jest: mock RxJs pipe 【发布时间】:2019-03-03 02:36:42 【问题描述】:

如何模拟更复杂的 RxJs 行为(在 NgRx 的上下文中)?

给定一个简单的组件(SomeComponent):

export class SomeComponent implements OnInit 
  foo$: Observable<any>;
  bar$: Observable<any>;

  constructor(private store: Store<State>) 

  ngOnInit() 
    this.foo$ = this.store.pipe(select(getFooSelector));
    this.bar$ = this.store.pipe(select(getBarSelector));
  

我想以一种方式模拟商店:

根据传递的选择器,模拟存储返回不同的值。 窥探将哪个参数(选择器)传递给select 运算符。

根据传递的选择器,模拟存储返回不同的值

我会认为它是这样的:

store.pipe = jest.fn(selectOperator => 
  switch (selectOperator.arguments[0]) 
    case getFooSelector:
      return foo;
    case getBarSelector:
      return bar;
  

窥探将什么参数(选择器)传递给select 运算符。

类似的东西:

const spy = jest.spyOn(store, 'pipe');
expect(spy.mock.calls[0]).toHaveBeenCalledWith(select(getFooSelector));
expect(spy.mock.calls[1]).toHaveBeenCalledWith(select(getBarSelector));

总结

我知道这两个示例都是伪代码,但我希望它们能证明我想要实现的目标。如果我的方法完全错误,请对此发表评论。

【问题讨论】:

关于 Ngrx repo 的讨论正在进行中,试图获得官方支持来测试类似的东西。还没有完成,但我已经发布了我现在使用的内容。我使用的是 jasmine,而不是 Jest,但它可能会帮助您构建一个等效的:github.com/ngrx/platform/issues/915#issuecomment-414601899 感谢您的参考。可悲的是,我可以让它们中的任何一个正常工作。你的例子给了我: InvalidPipeArgument: 'function ...' for AsyncPipe 【参考方案1】:

使用 NGRX v8.6.0,您应该能够执行以下操作:

let fixture: ComponentFixture<SomeComponent>;
let mockStore: MockStore<State>;

beforeEach(() => 
    TestBed.configureTestingModule(
        providers: [provideMockStore()],
        declarations: [SomeComponent],
    );

    fixture = TestBed.createComponent(SomeComponent);
    mockStore = TestBed.get(Store);
    fixture.detectChanges();
);

it('should have a value of foo', done => 
    mockStore.overrideSelector(getFooSelector, 'foo');

    foo$.subscribe(res => 
        done();
        expect(res).toBe('foo');
    );
);

it('should have a value of bar', done => 
    mockStore.overrideSelector(getBarSelector, 'bar');

    bar$.subscribe(res => 
        done();
        expect(res).toBe('bar');
    );
);

https://ngrx.io/guide/store/testing

【讨论】:

【参考方案2】:

使用RxJs Marbles 使用 NgRx 测试 RxJ。

欲了解更多信息,请阅读RxJS Marble Testing: RTFM 并查看Jest Testing - Jesse Sanders、Reactive Testing Strategies with NgRx - Brandon Roberts & Mike Ryan

实现使用jest.fn().mockImplementationOnce

store.pipe = jest.fn()
   .mockImplementationOnce(foo)
   .mockImplementationOnce(bar)

expect(store.pipe).toHaveBeenCalledWith(select(getFooSelector));
expect(store.pipe).toHaveBeenCalledWith(select(getBarSelector));

【讨论】:

感谢您的回复。可悲的是,它对我不起作用。我知道它期望 Function selectOperator 但得到了... Function selectOperator。此外,如果我正确理解您的答案,则没有简单的方法可以切换结果。它强烈依赖于调用store.pipe 的顺序。

以上是关于笑话:模拟 RxJs 管道的主要内容,如果未能解决你的问题,请参考以下文章

Angular/Rxjs 管道异步不适用于 s-s-r?

RxJS if-else 类似管道过滤

如何使用jasmine-marbles测试rxjs管道中的timeout()

从角度服务通过管道传输时,rxjs catchError 不起作用

我可以将笑话代码覆盖率添加到来自管道的 Bitbucket 拉取请求中的报告吗

RxJs 管道和 lettable 运算符“map”:“void”类型的“this”上下文不可分配给“Observable<>”类型的方法“this”