我们说我有这个
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;
});
});
}
}
我的组件实际上工作得很好。问题是我想对它进行单元测试,但我无法弄清楚如何模拟this.route.parent
对象。这是我的测试失败
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();
});
});
测试因此错误而失败
TypeError: undefined is not an object (evaluating 'this._routerState.parent')
答案 0 :(得分:37)
使用TestBed
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [YourComponent],
imports: [],
providers: [
{
provide: ActivatedRoute, useValue: {
params: Observable.of({ id: 'test' })
}
}
]
})
.compileComponents();
}));

答案 1 :(得分:17)
AcitvatedRoute是一个根据angular2 docs的界面,所以我所做的是实现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<UrlSegment[]>;
params : Observable<Params>;
queryParams : Observable<Params>;
fragment : Observable<string>;
data : Observable<Data>;
outlet : string;
component : Type<any>|string;
routeConfig : Route;
root : ActivatedRoute;
parent : ActivatedRoute;
firstChild : ActivatedRoute;
children : ActivatedRoute[];
pathFromRoot : ActivatedRoute[];
toString() : string{
return "";
};
}
并且只需替换我ActivatedRoute
的测试中的MockActivatedRoute
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);
});
答案 2 :(得分:8)
对于此问题的新用户,angular.io文档涵盖了此方案。见here
根据上述文件:
创建ActivatedRouteStub
类,用作ActivatedRoute
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { convertToParamMap, ParamMap, Params } from '@angular/router';
/**
* An ActivateRoute test double with a `paramMap` observable.
* Use the `setParamMap()` method to add the next `paramMap` value.
*/
export class ActivatedRouteStub {
// Use a ReplaySubject to share previous values with subscribers
// and pump new values into the `paramMap` observable
private subject = new ReplaySubject<ParamMap>();
constructor(initialParams?: Params) {
this.setParamMap(initialParams);
}
/** The mock paramMap observable */
readonly paramMap = this.subject.asObservable();
/** Set the paramMap observables's next value */
setParamMap(params?: Params) {
this.subject.next(convertToParamMap(params));
};
}
然后在测试类中使用stub,如下所示:
activatedRoute.setParamMap({ id: '1234' });
答案 3 :(得分:3)
要在每个“ it”块中自定义模拟的ActivatedRoute数据,请结合凯文·布莱克(Kevin Black)的建议
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [YourComponent],
imports: [],
providers: [
{
provide: ActivatedRoute, useValue: {
queryParams: of({ id: 'test' })
}
}
]
})
.compileComponents();
}));
和it('')块中的以下代码,然后使用Fixture.detectChanges()实例化组件
it('test', fakeAsync(() => {
let activatedRoute: ActivatedRoute = fixture.debugElement.injector.get(ActivatedRoute);
activatedRoute.queryParams = of({ firstName: 'john', lastName: 'smith' });
fixture.detectChanges(); // trigger ngOninit()
tick();
}));
答案 4 :(得分:2)
对于要从 ActivatedRouteSnapshot 读取查询参数的情况,如:
this.someProperty = this.route.snapshot.data.query['paramKey'];
下面的代码将有助于将查询参数数据输入到路由中的测试
{
provide: ActivatedRoute,
useValue: {
snapshot: {
data: {
query: {
paramKey: 'paramValue'
}
}
}
}
}
答案 5 :(得分:2)
Angular 9 版本
创建您的模拟:
const mockActivatedRoute = {
parent: {
paramMap: of(convertToParamMap(
{ organization: 'fakeOrganization' }
))}
};
提供它作为激活的路由
providers: [{ provide: ActivatedRoute, useValue: mockActivatedRoute }]
测试一下
describe('ngOnInit', () => {
it('should get the route parameter', fakeAsync(() => {
component.ngOnInit();
expect(component.organization).toBe('fakeOrganization');
}));
});'
正在测试的代码
ngOnInit(): void {
this.route.parent.paramMap.subscribe(params => {
this.organization = params.get('organization');
});
}
答案 6 :(得分:1)
您还可以简单地播放{params: {searchTerm: 'this is not me'}} as any) as ActivatedRouteSnapshot
删除代码
(service.resolve(({params: {id: 'this is id'}} as any) as ActivatedRouteSnapshot,
{} as RouterStateSnapshot)as Observable<xyzResolveData>)
.subscribe((data) => {
expect((data as xyzResolveData).results).toEqual(xyzData.results);
});
答案 7 :(得分:0)
基于@S.Galarneau 接受的答案,这里是更新的 ActivatedRoute 接口(angular 4+),带有访问修饰符,仅使用少数类型,以及使用 providers 数组并与 TestBed 集成:
这非常适合创建模拟界面并使用 providers 数组来使用您的 ActivatedRoute 版本:
running = True
while running:
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
elif e.type == pygame.KEYDOWN:
# print key
print(e.key)
# print unicode representation
print(e.unicode)
# print user firendly name
print(pygame.key.name(e.key))
和TestBed和Providers数组一起使用,只处理fragment属性,像这样:
export class MockActivatedRoute implements ActivatedRoute{
public snapshot;
public url;
public params;
public queryParams: Observable<Params>;
public fragment: Observable<string>;
public data;
public outlet;
public component;
public paramMap;
public queryParamMap;
public routeConfig;
public root;
public parent;
public firstChild;
public children;
public pathFromRoot;
public toString(): string {
return '';
};
}