如何模拟@ ngrx / store?

时间:2017-04-04 18:33:49

标签: mocking jasmine rxjs ngrx

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

  

TypeError:undefined不是config / spec-bundle.js中的对象(评估'this.store.unsubscribe')

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

以下是以下几行:

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 }
        ]
  })

告诉我你是否想要更多信息。提前谢谢。

2 个答案:

答案 0 :(得分:8)

你可以通过多种方式嘲笑商店,你做的事情将取决于你想要测试的方式。

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

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

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

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

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并将其添加到TestBed的{​​{1}}:

providers

在组件中注入模拟的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上致电unsubscribe;你应该在订阅商店时返回的Subscription对象上调用它 - 如另一个答案所述。

答案 1 :(得分:1)

问题可能在于您取消订阅。您应该在实际订阅上调用取消订阅而不是您的可观察/商店。 例如。如果你有这样的订阅:

>>> pickle.dumps(y)
(b'\x80\x03cmultiprocessing.managers\n'
b'RebuildProxy\n'
b'q\x00(cmultiprocessing.managers\n'
b'AutoProxy\n'
b'q\x01cmultiprocessing.managers\n'
b'Token\n'
b'q\x02)\x81q\x03X\x05\x00\x00\x00Queueq\x04X$\x00\x00\x00/tmp/pymp-pog4bhub/listener-0_uwd8c9q\x05X\t\x00\x00\x00801b92400q\x06\x87q\x07bX\x06\x00\x00\x00pickleq\x08}q\tX\x07\x00\x00\x00exposedq\n'
b'(X\x05\x00\x00\x00emptyq\x0bX\x04\x00\x00\x00fullq\x0cX\x03\x00\x00\x00getq\rX\n'
b'\x00\x00\x00get_nowaitq\x0eX\x04\x00\x00\x00joinq\x0fX\x03\x00\x00\x00putq\x10X\n'
b'\x00\x00\x00put_nowaitq\x11X\x05\x00\x00\x00qsizeq\x12X\t\x00\x00\x00task_doneq\x13tq\x14stq\x15Rq\x16.\n')

您取消订阅如下:

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

另外,不确定你是否遗漏了一些代码,但是你嘲笑你的商店的方式,它可能足以只使用实际的商店,只是间谍派遣等。