如何在 Angular 中使用 Jasmine 测试 RxJS switchMap?

Posted

技术标签:

【中文标题】如何在 Angular 中使用 Jasmine 测试 RxJS switchMap?【英文标题】:How to test RxJS switchMap with Jasmine in Angular? 【发布时间】:2022-01-16 11:45:10 【问题描述】:

在我的 Angular 项目中,我的一个组件中有这段代码:

  delete(post: PostInterface): void 
    const delete$ = this.appDataService.proxy
      .delete(post, this.paginate)
      .pipe(switchMap(() => this.loadDatas()));

    this.subscriptions.add(
      this.appDataService.start(delete$, 'delete').subscribe()
    );
  

在我的规范文件中:

describe('PostListComponent', () => 
  let component: PostListComponent;
  let fixture: ComponentFixture<PostListComponent>;
  let debugElement: DebugElement;

  beforeEach(async () => 

    await TestBed.configureTestingModule(
      // ...
    )
    .compileComponents()
    .then(() => 
      fixture = TestBed.createComponent(PostListComponent);
      component = fixture.componentInstance;
      debugElement = fixture.debugElement;

      fixture.detectChanges();
    );
  );

  describe('functions', () => 
    it('should be delete with proxy.delete() and reload datas', fakeAsync(() => 
      spyOn(component, 'loadDatas');

      component.delete(1);

      flush();

      expect(component.loadDatas).toHaveBeenCalledTimes(1);
    ));
  );
);

在实际环境中switchMap 工作正常,但在测试中失败并显示以下消息:

PostListComponent > functions > should be delete with proxy.delete() and reload datas

Expected spy loadDatas to have been called once. It was called 0 times.

为什么我的测试中没有运行switchMap?有什么想法吗?

【问题讨论】:

这个答案不能解决你的问题吗? ***.com/questions/49910827/… @S.Hashiba 不,我在提问之前试过了 【参考方案1】:

测试没有按预期工作的原因可能在于您没有subscribe Observable。

订阅启动流,即触发执行嵌入在 Observable 链中的任何代码。

所以,你可能想试试这个版本的测试,看看情况是否有所改善

 describe('functions', () => 
    it('should be delete with proxy.delete() and reload datas', (done) => 
      spyOn(component, 'loadDatas');

      component.delete(1).subscribe(
        next: err => done(err),
        complete: () => 
           expect(component.loadDatas).toHaveBeenCalledTimes(1);
           done();
        
      );

      flush();

    );
  );

如您所见,我没有使用 fakeAsync,我假设 delete 实际上已被执行。

【讨论】:

component.delete() 是无效的。不是可观察的。在这个函数中,订阅就在那里。 再次阅读问题后,我看到delete 返回了一个空白。同时我想知道this.appDataService.start(delete$, 'delete').subscribe() 是否真的触发了一些异步逻辑。如果此代码异步执行,则expect 逻辑可能在异步逻辑完成之前执行,因此在loadDatas 执行之前。 是的,但是我该如何解决这个问题?需要重新构建组件代码以使其可测试,还是有其他方法可以以这种形式对其进行测试? 我会将代码移动到外部服务,通过依赖注入传递给组件,因此组件只需要以某种方法订阅或使用async 管道。另一方面,该服务是一个更简单的 Typscript 类,您可以使用我的回复中显示的技术对其进行测试 这听起来像是对代码的重构,而不是 switchMap 问题的解决方案。

以上是关于如何在 Angular 中使用 Jasmine 测试 RxJS switchMap?的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 中使用 Jasmine 使用 *ngIf 指令时,如何对元素是不是可见进行单元测试

Jasmine 2.0 async done() 和 angular-mocks inject() 在同一个测试 it()

如何使用 Jasmine 为私有方法编写 Angular / TypeScript 单元测试

如何在 Angular 7 中使用 Karma/Jasmine 为 App_Initializer 编写单元测试用例

Angular 7:如何在 Jasmine 单元测试中解决 Hammer.js 依赖项

如何在不使用 Angular 的 spyOn 的情况下检查服务中的方法是不是在 Jasmine 单元测试中被调用?