可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Let's say I have this
export class QuestionnaireQuestionsComponent { questions: Question[] = []; private loading:boolean = true; constructor( private route: ActivatedRoute, public questionnaireService:QuestionnaireService) {} ngOnInit(){ this.route.parent.params.subscribe((params:any)=>{ this.questionnaireService.getQuestionsForQuestionnaire(params.id).subscribe((questions)=>{ this.questions = questions; this.loading = false; }); }); } }
My component is actually working pretty well. Problem is that I want to unit test it but I can't figure out how to mock the this.route.parent
object. Here's my test that fails
beforeEach(()=>{ route = new ActivatedRoute(); route.parent.params = Observable.of({id:"testId"}); questionnaireService = jasmine.createSpyObj('QuestionnaireService', ['getQuestionsForQuestionnaire']); questionnaireService.getQuestionsForQuestionnaire.and.callFake(() => Observable.of(undefined)); component = new QuestionnaireQuestionsComponent(route, questionnaireService); }); describe("on init", ()=>{ it("must call the service get questions for questionnaire",()=>{ component.ngOnInit(); expect(questionnaireService.getQuestionsForQuestionnaire).toHaveBeenCalled(); }); });
The test fails with this error
TypeError: undefined is not an object (evaluating 'this._routerState.parent')
回答1:
Using TestBed
beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [YourComponent], imports: [], providers: [ { provide: ActivatedRoute, useValue: { params: Observable.of({ id: 'test' }) } } ] }) .compileComponents(); }));
回答2:
AcitvatedRoute is an interface according to angular2 docs, so what I did is implements a MockActivatedRoute
import {Observable} from 'rxjs'; import {Type} from '@angular/core'; import {ActivatedRoute,Route,ActivatedRouteSnapshot,UrlSegment,Params,Data } from '@angular/router'; export class MockActivatedRoute implements ActivatedRoute{ snapshot : ActivatedRouteSnapshot; url : Observable; params : Observable; queryParams : Observable; fragment : Observable; data : Observable; outlet : string; component : Type|string; routeConfig : Route; root : ActivatedRoute; parent : ActivatedRoute; firstChild : ActivatedRoute; children : ActivatedRoute[]; pathFromRoot : ActivatedRoute[]; toString() : string{ return ""; }; }
and just replace the ActivatedRoute
in my tests for MockActivatedRoute
like this
beforeEach(()=>{ route = new MockActivatedRoute(); route.parent = new MockActivatedRoute(); route.parent.params = Observable.of({id:"testId"}); questionnaireService = jasmine.createSpyObj('QuestionnaireService', ['getQuestionsForQuestionnaire']); questionnaireService.getQuestionsForQuestionnaire.and.callFake(() => Observable.of(undefined)); component = new QuestionnaireQuestionsComponent(route, questionnaireService); });
回答3:
You can also simple plass {params: {searchTerm: 'this is not me'}} as any) as ActivatedRouteSnapshot
detailds code
(service.resolve(({params: {id: 'this is id'}} as any) as ActivatedRouteSnapshot, {} as RouterStateSnapshot)as Observable) .subscribe((data) => { expect((data as xyzResolveData).results).toEqual(xyzData.results); });