我正在观察一种奇怪的行为。我有一个使用QuestionManagementService
的组件,并希望在规格中使用其模拟,但是Angular会同时创建真实和模拟服务!
我的组件使用QuestionManagementService
constructor(..., private questionManagementService: QuestionManagementService,...) {
/*
In spec, this prints QuestionManagementService instead of MockQuestionManagementService!!!!
*/
console.log('question mgmt in constructor ',questionManagementService);
this.supportedTags=new SupportedTags([]);
}
ngOnInit(){
....
let subscription = this.questionManagementService.getSupportedTags(this.tagId);//remove hardcoding.
}
要对组件进行单元测试,我创建了QuestionManagementService
class MockQuestionManagementService{
questionsArray$: Observable<Result>;
question$: Observable<Result>;
tags$:Observable<Result>;
addQuestion$:Observable<Result>;
questionsArraySubject: BehaviorSubject<Result>; //to send list of questions
questionSubject: BehaviorSubject<Result>; //to send details of a question
tagsSubject: BehaviorSubject<Result>; //to send details of a question
addQuestionSubject:BehaviorSubject<Result>;
getSupportedTags(tagId:TagId):any {
console.log("In mock QuestionManagementService: getSupportedTags: ",tagId);
let tag1 = new Tag('c1','s1','t1');
let tag2 = new Tag('c2','s2','t2');
let tag3 = new Tag('c3','s3','t3');
let tags:Tag[] = [tag1,tag2,tag3];
let supportedTags = new SupportedTags(tags);
this.tagsSubject.next(new Result('success',supportedTags));
}
constructor(){
/*You'll see in the image the first question management service is created, then this one!!!
*/
console.log("created mock service");
this.questionsArraySubject = new BehaviorSubject<Result>(new Result('initial',{})); //A Subject can act both as an Observable and an Observer
this.questionSubject = new BehaviorSubject<Result>(new Result('initial',{}));
this.tagsSubject = new BehaviorSubject<Result>(new Result('initial',{}));
this.addQuestionSubject = new BehaviorSubject<Result>(new Result('initial',{}));
this.questionsArray$ = this.questionsArraySubject.asObservable(); //create Observable. Other components can subcribe to it now to get notifications/values
this.question$ = this.questionSubject.asObservable(); //create Observable. Other components can subcribe to it now to get notifications/values
this.tags$ = this.tagsSubject.asObservable();
this.addQuestion$ = this.addQuestionSubject.asObservable();
}
}
,并提到要在providers
describe('NewPracticeQuestionComponent', () => {
let component: NewPracticeQuestionComponent;
let fixture: ComponentFixture<NewPracticeQuestionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NewPracticeQuestionComponent,
DialogBoxComponent,
ShowErrorsComponent],
imports:[ReactiveFormsModule,HttpClientTestingModule],
providers:[WebToBackendInterfaceService,
HelperService,
AuthService,
{provide: QuestionManagementService, useClass:MockQuestionManagementService}] //QuestionManagementService is being created even though I have mentioned a different class
})
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: {
entryComponents: [DialogBoxComponent]/*DialogBoxComponent is created dynamically (imperatively), soit nee to be ddded in entryComponent*/
}
})
.compileComponents();
然后我得到了规范中的服务实例
fit('should get tags from the server on loading',()=>{
let newPracticeQuestionComponent = component;
let questionManagementService = TestBed.get(QuestionManagementService);
console.log('component is ',newPracticeQuestionComponent);
console.log('service is ',questionManagementService);
spyOn(questionManagementService,'getSupportedTags');
expect(newPracticeQuestionComponent.supportedTags["supported-tags"].length).toBe(0);
expect(questionManagementService.getSupportedTags).toHaveBeenCalledWith(newPracticeQuestionComponent.tagId);
expect(newPracticeQuestionComponent.supportedTags["supported-tags"].length).toBe(3);
规范未能说明Expected spy getSupportedTags to have been called with [ TagId({ course: 'coding' }) ] but it was never called.
,因为它是从getSupportedTags
而不是QuestionManagementService
调用MockQuestionManagementService
的,所以我知道它正在发生。但是Angular为什么同时创建QuestionManagementService
和MockQuestionManagementService
?可能是因为TestBed.overrideModule
做某件事很奇怪吗?