2017-04-04 30 views
2

我想单元测试一个组件。我正在使用@ ngrx/store和rxjs为了从我的组件更新我的商店。为此,我订阅并取消订阅商店。 我的单元测试与如何模拟@ ngrx/store?

TypeError: undefined is not an object (evaluating '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 } 
     ] 
    }) 

如果您需要更多信息,告诉我。提前致谢。

回答

5

有多种方法可以模拟商店,你所做的将取决于你想要测试的方式。

当我嘲笑在我的测试店里,我只对两两件事感兴趣:

  • 能够很容易地发出自己相关的测试的状态;和
  • 能够看到test.the

我不感兴趣的连接最多减速,因为他们在别处测试期间被分派到商店的任何行动,所以这是我做的。

我用这样的函数来创建一个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,并把它添加到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对象上调用它 - 如其他答案中所述。

+0

感谢您的回答。我尝试了你的方式,仍然有错误...正如我在其他答案中所说的,我已经在Subscription对象上调用了我的退订。 – Megan

1

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

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

您退订这样的:

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

另外,如果你遗漏了一些代码不知道,但你嘲笑你的店的方式,它很可能是足以仅仅使用实际的商店,并且只是在派遣等方面进行监视。

+1

感谢您的回答:)一些代码被遗漏了,因为我的组件和它的测试非常重要。我已经退订,因为你在你的评论中描述,所以我想知道我的错误是在其他地方... 'this.userStore = this.store.let(fromRoot.get).subscribe((state:any)=> {/ /导航到欢迎页面,如果连接});' – Megan