如何测试使用依赖项注射服务事件的NGRX效应

发布于 2025-02-02 21:19:26 字数 1373 浏览 4 评论 0 原文

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

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

constructor(private platformService: PlatformService) {
}

这确实很好,但是我真的不知道如何优雅地测试它。通常,我们尝试尽可能地设置测试模块。例如,

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.
    });
  });
});

可悲的是,这似乎不起作用,因为效果是在构造函数中创建的,因此我的事件流始终是空的,即使我在间谍中覆盖简历响应,也不会触发效果。

现在,我可以在the each(例如(UNDEFINED))中设置一个默认值,但是它在测试中并没有真正耦合,我无法使用AAA模式。

另一方面,我可能每次都可以创建一个新的效果实例,但这似乎有点过分?

有更好的方法吗? NGRX在动作流方面确实很好地解决了它,我想知道使用DI源是否有类似的效果解决方案。

I have following effect that uses the an observable source from a PlatformService provided by Angulars Dependency Injection.

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

constructor(private platformService: PlatformService) {
}

This works really well, but I do not really know how to test it elegantly. Usually we try to setup our TestingModule as unspecific as possible. 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

Sadly this does not seem to work as the effects are created in the constructor and therefore my event stream is always EMPTY and does not trigger the effect even if I overwrite the resume response in my spy.

Now I could set a default value in the beforeEach (e.G. of(undefined)) but then it is not really coupled in my tests and I cant use the AAA pattern.

On the other hand I could probably create a new Effects instance every time but that seems a bit overkill not?

Is there a better method? NgRx solved it really well with the actions stream and I wonder if there is a similar solution for effects using sources from DI.

, () => { 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. }); }); });

Sadly this does not seem to work as the effects are created in the constructor and therefore my event stream is always EMPTY and does not trigger the effect even if I overwrite the resume response in my spy.

Now I could set a default value in the beforeEach (e.G. of(undefined)) but then it is not really coupled in my tests and I cant use the AAA pattern.

On the other hand I could probably create a new Effects instance every time but that seems a bit overkill not?

Is there a better method? NgRx solved it really well with the actions stream and I wonder if there is a similar solution for effects using sources from DI.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

溺深海 2025-02-09 21:19:26

有关更多信息,请参见,


it('fetch$ dispatches a success action', () => {
//

For more info see, 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,
            }),
        ),
    ]);
});
东走西顾 2025-02-09 21:19:26

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

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

这对这种情况有效,但是一旦我尝试使用返回返回a的服务方法做同样的事情承诺此解决方案不再起作用。

, () => { 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(); }); }); }); });

这对这种情况有效,但是一旦我尝试使用返回返回a的服务方法做同样的事情承诺此解决方案不再起作用。

I tried a bit more and thought that the actions stream is probably just a subject and I could do the same for my own service method:

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

This works for this case but as soon as I try to do the same with a service method that returns a promise this solution does not work anymore.

, () => { 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(); }); }); }); });

This works for this case but as soon as I try to do the same with a service method that returns a promise this solution does not work anymore.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文