如何测试使用依赖注入服务事件的 NgRx Effect

How to test NgRx Effect that uses event from dependency injected service

我有以下效果,它使用来自 Angulars 依赖注入提供的 PlatformService 的可观察源。

public resume$ = createEffect(() => {
  return this.platformService.resume().pipe(mapTo(PlatformActions.appResumed()));
});

constructor(private platformService: PlatformService) {
}

这确实很好用,但我真的不知道如何优雅地测试它。通常我们会尝试将我们的 TestingModule 设置得尽可能不具体。 e.G

describe('PlatformEffects', () => {
  let effects: PlatformEffects;
  let platformServiceSpy: SpyObj<PlatformService>;

  beforeEach(() => {
    platformServiceSpy = jasmine.createSpyObj({
      resume: EMPTY
    });

    TestBed.configureTestingModule({
      providers: [
        PlatformEffects,
        {
          provide: PlatformService,
          useValue: platformServiceSpy
        }
      ]
    });

    effects = TestBed.inject(PlatformEffects);
  });

  it('should be created', () => {
    expect(effects).toBeTruthy();
  });

  describe('resume$', () => {
    it('dispatches appResumed action on resume event', (done) => {
      // AAA: This test should setup the response from the platformService so the arrange setup is coupled in the test.
    });
  });
});

遗憾的是,这似乎不起作用,因为效果是在构造函数中创建的,因此我的事件流始终为 EMPTY,即使我覆盖了间谍中的恢复响应也不会触发效果。

现在我可以在 beforeEach 中设置一个默认值(例如 of(undefined)),但是它在我的测试中并没有真正耦合,我不能使用 AAA 模式。

另一方面,我可能每次都创建一个新的 Effects 实例,但这似乎有点过分了不是吗?

有没有更好的方法? NgRx 用动作流很好地解决了这个问题,我想知道是否有类似的解决方案来处理使用来自 DI 的源的效果。

有关详细信息,请参阅 https://timdeschryver.dev/blog/testing-an-ngrx-project#effects


it('fetch$ dispatches a success action', () => {
    //  The Effect Actions stream is created by instantiating a new `ActionsSubject`
    const actions = new ActionsSubject();
    const effects = new CustomersEffects(actions, newCustomerService());

    //  Subscribe on the effect to catch emitted actions, which are used to assert the effect output
    const result: Action[] = [];
    effects.fetch$.subscribe((action) => {
        result.push(action);
    });

    const action = customerPageActions.enter({ customerId: '3' });
    actions.next(action);

    expect(result).toEqual([
        customersApiActions.fetchCustomerSuccess(
            newCustomer({
                id: action.customerId,
            }),
        ),
    ]);
});

我尝试了更多,认为操作流可能只是一个主题,我可以为我自己的服务方法做同样的事情:

describe('PlatformEffects', () => {
  let effects: PlatformEffects;
  let platformServiceSpy: SpyObj<PlatformService>;

  let resumeSubject: ReplaySubject<any>;

  beforeEach(() => {
    // create new subject that can be used as an event emitter
    resumeSubject = new ReplaySubject<any>();

    platformServiceSpy = jasmine.createSpyObj({
      resume: resumeSubject.asObservable()
    });

    TestBed.configureTestingModule({
      providers: [
        PlatformEffects,
        {
          provide: PlatformService,
          useValue: platformServiceSpy
        }
      ]
    });

    effects = TestBed.inject(PlatformEffects);
  });

  it('should be created', () => {
    expect(effects).toBeTruthy();
  });

  describe('resume$', () => {
    it('dispatches appResumed action on resume event', (done) => {
      // emit new test string in resume subject
      resumeSubject.next('test');

      effects.resume$.subscribe((res) => {
        expect(res).toEqual(PlatformActions.appResumed());
        done();
      });
    });
  });
});

这适用于这种情况,但一旦我尝试对 returns 承诺此解决方案不再有效的服务方法执行相同操作。