【问题标题】:How do I mock selectors in nrgx 8 unit tests?如何在 nrgx 8 单元测试中模拟选择器?
【发布时间】:2020-03-06 07:44:43
【问题描述】:

我正在学习使用 Jest 为 ngrx8 应用程序编写单元测试。

我正在测试一个订阅了 ngOnInit 中选择器的组件:

ngOnInit(): void {
  this.store.pipe(select(someSelector(this.parameter))).subscribe((res: 
    // some logic here
  });
}

在 .spec.ts 文件中,我将 provideMockStore 放入 TestBed 配置中:

TestBed.configureTestingModule({
    // ...
    providers: [
      provideMockStore({
        initialState, // defined somewhere above
        selectors: [
          {
            selector: someSelector('param'),
            value: {a: 'b', c: 'd'}
          }
        ]
      })
    ]
    // ...
}).compileComponents();;

所以我希望在运行这个单元测试时,我应该在组件 .ts 文件中输入订阅(“这里的一些逻辑”部分),res 将等于 {a: 'b', c: 'd'}

这不会发生,而是忽略模拟选择器并使用真实的选择器。

我尝试过的事情:

  • store.overrideSelector(someSelector('param'), {a: 'b', c: 'd')

  • fixture.detectChanges()await fixture.whenStable()放在不同的地方

现在我别无选择,NGRX documentation 几乎没有涵盖任何内容。

【问题讨论】:

  • 没有ngrx门面的生活很难......我建议你做一些重构并使用门面。它使测试组件变得轻而易举,因为您可以将商店模拟与组件依赖模拟分开。

标签: angular unit-testing jestjs ngrx


【解决方案1】:

模拟选择器似乎不是最好的解决方案。 最好模拟商店本身。

您可以提供状态:

provideMockStore({ initialState: your_state })

mockStore.setState(your_state);

mockStore.setState(...) 允许您在测试中的商店中进行具有不同价值的测试。

但是如果您有一个复杂的商店,我建议您执行以下操作:

  • 创建一个类,您将在其中拥有模拟存储状态:MockStoreState

type RecursivePartial<T> = {
  [P in keyof T]?:
  T[P] extends (infer U)[] ? RecursivePartial<U>[] :
    T[P] extends object ? RecursivePartial<T[P]> :
      T[P];
};

export class MockStoreState {
  private store_a: RecursivePartial<Store_A>;
  private store_b: RecursivePartial<Store_b>;

  build(): any {
    const defaultStore_a = {
      ...
    };
    const defaultStore_b = {
      ...
    };

    return {
      store_a: { ...defaultStore_a , ...this.store_a},
      store_b: { ...defaultStore_b , ...this.store_b },
    };
  }

  setStore_a(value: RecursivePartial<Store_A>): Store_A_State {
    this.store_a= value;
    return this;
  }

  setStore_b(value: RecursivePartial<DatasourceState>): Store_B_State {
    this.store_b= value;
    return this;
  }
}
  • 在测试中设置你的商店的状态:
describe(MyComponent.name, () => {
   ...
   let mockStore: MockStore<any>;

   beforeEach(() => {
       ...
       mockStore = TestBed.get(Store);
   })


   it('...', () => {
     const state = new MockStoreState().setStore_a({...})
    .build();

    mockStore.setState(state);

   // HERE you have set the data in your store.
   })
}

【讨论】:

  • 我正在尝试您提出的第一个解决方案。如果我在第一个 fixture.detectChanges 之前设置状态,它会起作用但是在第一个 fixture.detectChanges() 之后设置状态不会触发任何订阅 - 所以我无法测试组件是否响应状态更改。我是否需要手动运行某些功能才能做到这一点?
猜你喜欢
  • 2021-04-24
  • 1970-01-01
  • 2021-01-07
  • 2017-06-14
  • 1970-01-01
  • 2019-09-08
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
相关资源
最近更新 更多