【问题标题】:How to mock @ngrx/store?如何模拟@ngrx/store?
【发布时间】:2017-08-30 02:43:50
【问题描述】:

我想对一个组件进行单元测试。我正在使用 @ngrx/store 和 rxjs 来从我的组件更新我的商店。为此,我订阅和取消订阅商店。 我的单元测试失败了

TypeError: undefined is not an object (evalating 'this.store.unsubscribe') in config/spec-bundle.js

我无法找到正确模拟我的商店及其事件发射器的方法。

以下是以下几行:

app.component.ts:

  ngOnDestroy() {
    // unsubscribe the observable
    this.userStore.unsubscribe();
  }

app.component.spec.ts:

我如何模拟商店:

        export class MockStore extends Subject<fromRoot.State> implements Store <fromRoot.State> {}

我如何配置:

        TestBed.configureTestingModule({
        imports: [
            FormsModule,
            ReactiveFormsModule,
            StoreModule.provideStore(reducer)
        ],
        declarations: [LoginComponent],
        providers: [
            BaseRequestOptions,
            MockBackend,
            { provide: AuthService, useValue: authServiceStub },
            { provide: LoginService, useValue: loginServiceStub },
            { provide: LoggerService, useValue: loggerServiceStub },
            {
                provide: Http, useFactory: (backend: ConnectionBackend,
                    defaultOptions: BaseRequestOptions) => {
                    return new Http(backend, defaultOptions);
                }, deps: [MockBackend, BaseRequestOptions]
            },
            { provide: Router, useClass: MockRouter }
        ]
  })

如果您想了解更多信息,请告诉我。提前致谢。

【问题讨论】:

    标签: mocking jasmine rxjs ngrx


    【解决方案1】:

    问题可能与您的退订有关。您应该取消订阅您的实际订阅,而不是您的 observable/store。 例如。如果您有这样的订阅:

    this.subscription = this._store
        .select('users')
        .subscribe(users => {
          this.users = users;
      });
    

    你这样退订:

      ngOnDestroy() {
        // unsubscribe the observable
        this.subscription.unsubscribe();
      }
    

    另外,不确定您是否遗漏了一些代码,但根据您模拟商店的方式,仅使用实际商店并监视调度等可能就足够了。

    【讨论】:

    • 感谢您的回答 :) 一些代码作为我的组件被遗漏了,它的测试非常重要。正如您在评论中描述的那样,我已经取消订阅,所以我想知道我的错误在其他地方...this.userStore = this.store.let(fromRoot.get).subscribe((state: any) =&gt; { // navigates to welcome page if connection });
    【解决方案2】:

    您可以通过多种方式模拟商店,具体操作取决于您要如何测试。

    当我在测试中模拟商店时,我只对两件事感兴趣:

    • 能够轻松发出与测试相关的状态;和
    • 能够看到在测试期间发送到商店的任何操作。

    我对连接减速器不感兴趣,因为它们在其他地方进行了测试,所以这就是我所做的。

    我使用这样的函数从两个Subject 实例创建Store

    import { Action, Store } from "@ngrx/store";
    import { Subject } from "rxjs/Subject";
    
    export function mockStore<T>({
      actions = new Subject<Action>(),
      states = new Subject<T>()
    }: {
      actions?: Subject<Action>,
      states?: Subject<T>
    }): Store<T> {
    
      let result = states as any;
      result.dispatch = (action: Action) => actions.next(action);
      return result;
    }
    

    beforeEach 中,我创建Store 并将其添加到TestBedproviders

    actions = new Subject<Action>();
    states = new Subject<AppState>();
    store = mockStore<AppState>({ actions, states });
    
    TestBed.configureTestingModule({
      imports: [EffectsTestingModule],
      providers: [
        {
          provide: Store,
          useValue: store
        },
        ...
      ]
    });
    

    在组件中注入模拟的Store - 或效果,或您正在测试的任何东西 - 然后在测试中发出特定状态很简单 - 使用 states 主题 - 很容易检查看到通过订阅actions 主题,任何预期的操作都已发送。

    关于您的错误,您不应该在Store 上调用unsubscribe;您应该在订阅商店时返回的 Subscription 对象上调用它 - 如另一个答案中所述。

    【讨论】:

    • 感谢您的回答。我尝试了您的方式,但仍然出现错误......正如我在另一个答案中所说,我已经在 Subscription 对象上调用了我的取消订阅。
    猜你喜欢
    • 1970-01-01
    • 2017-10-08
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 2017-11-03
    • 1970-01-01
    • 2019-06-07
    相关资源
    最近更新 更多