【问题标题】:How to test multiple withLatestFrom store injections in NgRx-Effects?如何在 NgRx-Effects 中测试多个 withLatestFrom 商店注入?
【发布时间】:2019-08-19 02:48:31
【问题描述】:

在我们的 Angular Web 应用中,我们有一些 NgRx 效果,它们使用来自我们商店不同部分的不同信息。为此,我们使用推荐的withLatestFrom-approach:

withLatestFrom(
   this.store.pipe(select(...)),
   this.store.pipe(select(...)),
   ...
)

虽然这种方法似乎在生产中运行良好,但对效果进行单元测试时感觉很糟糕。

对于我们的单元测试,我们目前正在使用 jasmine-marbles、jasmine spy-objects 和 ngrx MockStore (NgRx 7+)。困难的部分是提供必要的存储状态,以便选择器能够正常工作。

EXAMPLE-EFFECT,我们没有单元测试:

@Effect()
getStammdatenDetails$: Observable<Action> = this.actions$.pipe(
   ofType(StammdatenItemDetailActionTypes.REQUEST_DETAILS),
   withLatestFrom(
      this.store.pipe(select(fromRoot.getMetadata)),
      this.store.pipe(select(fromRoot.getCustomerId)),
      this.store.pipe(select(fromRoot.getRouterParams))
   ),
   mergeMap(([action, metadata, customerId, params]) => {
      *effect logic*
   })
);

也许这里有人可以提供更多见解或指向我们缺少的文档的有用链接?

如果有方便的方法来对此类效果进行单元测试,或者如何将这些效果重构为更“可测试”(无需将问题转移到我们无法测试的另一段代码),我将非常感谢任何帮助之后)。

【问题讨论】:

  • 这是您测试效果的第一步,还是您之前尝试过一些模式?
  • 我们已经为我们不太复杂的效果设置了一些测试,但老实说我不太确定你说的是哪种模式。介意分享一本好书吗?
  • 好的,给我1小时我会找到一些东西
  • 请告诉我,你在 Karma 中使用过 TestBet、Spy 和异步单元测试之类的东西吗?
  • 我们使用所需的 Spys(用于使用的服务)设置了 TestBed,并使用 fakeAsync() 环境进行需要它的测试。

标签: angular typescript unit-testing testing ngrx


【解决方案1】:

我建议这样做:

describe('ChapterEffects', () => {
  const actions$ = new Subject<any>();
  let effects: ChapterEffects;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        TestedEffects,
        provideMockActions(() => actions$),
        ...otherMocks,
      ],
    });

    effects = TestBed.get(ChapterEffects);
  });

  it('', () => {

  });
});

测试效果:

  @Effect()
  fetchData$ = this.actions$.pipe(
    ofType<FetchAction>(ActionTypes.FetchAction),
    switchMap(({ payload }) => {
      return this.someService
        .get(payload)
        .pipe(
          map((data) => new LoadAction(data)),
          catchError(() => new ErrorAction()),
        );
    }),
  );

这就是你的效果和测试。您想测试 FetchAction 是否会调用 get 请求并在请求完成时加载 LoadAction

首先是在 testBet 中模拟 someService:

const otherMocks = [ { provide: SomeService, useValue: { get: () => of(42)} }, ]

现在在您的测试运行时 this.someService 将是 { get: () =&gt; of(42)} }

现在让我们模拟 FetchAction。在测试中actions$ 是一个主题,因此您可以调用actions$.next(new FetchRequest(7))(7 是有效负载)。

那么输出效果应该发出 42 的 LoadAction,所以:

it('', (done) => {
  effect.fetchData$.subscribe(action => {
    expect(action.payload).toEqual(42);
  }
  done()
  actions$.next(7);
});

【讨论】:

  • 虽然这是对如何测试 ngrx 效果的一个很好的总结,但我在我的问题中苦苦挣扎的部分是,如何方便地测试使用商店部分的效果(因此 withLatestFrom(this.store.pipe(select(...))) )。一种方法是完全模拟商店,但由于我们的商店结构已经很大,我觉得必须有一个更方便的解决方案。
  • 这将与SomeService 中的情况几乎相同。 this.store 取自 DI,因此您可以轻松地通过 { provide: Store, useValue: new BehaviorSubject() } 模拟它,并且使用 BehaviorSubject 您可以推送当前的模拟状态。
  • 如前所述,我已经知道这个选项(但我更愿意使用来自ngrx的MockStore)。我们的 store 结构嵌套很深,因此为不同的测试用例构建这样的 store 感觉就像是一个很大的开销。但也许目前没有其他方法......我会接受这个答案感谢您的帮助,非常感谢!
  • 我知道,hoverer 我不想向你推荐我没有检查我的应用程序的模式。对我来说,它并不完美,因为需要大量代码,但它运行良好。
  • 纯粹出于兴趣:你能说出那些你不能推荐的模式吗?我想阅读它们!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-16
  • 2019-09-30
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
相关资源
最近更新 更多