如何对 Angular 2 个路由参数进行单元测试
How to Unit Test Angular 2 routing params
假设我想简单地对一个组件进行单元测试,该组件采用从部分路由获取的参数。例如,我的组件的 ngOnInit 看起来像这样:
ngOnInit() {
this.route.parent.params.switchMap((params: Params) => this.service.getProject(params['projectId']))
.subscribe((project: Project) => this.update(project));
}
我现在如何:
1:设置我的测试,以便组件创建完全有效,这样我就可以对其他部分进行单元测试
使用答案进行编辑 - 示例 ActivatedRouteStub 应该使用也具有可观察参数的父对象进行扩展,我应该使用 useClass 而不是 useValue(忘记改回去):
@Injectable()
export class ActivatedRouteStub {
// ActivatedRoute.params is Observable
private subject = new BehaviorSubject(this.testParams);
params = this.subject.asObservable();
// Test parameters
private _testParams: {};
get testParams() { return this._testParams; }
set testParams(params: {}) {
this._testParams = params;
this.subject.next(params);
}
// ActivatedRoute.snapshot.params
get snapshot() {
return { params: this.testParams };
}
// ActivatedRoute.parent.params
get parent() {
return { params: this.subject.asObservable() };
}
}
2: 在我的单元测试中为 projectId 提供一个值?
angular2 文档中的示例似乎不适用于 switchMap,甚至根本不起作用(我从那里使用了 ActivatedRouteStub,但到目前为止运气不好 - params 始终未定义)。
编辑答案:
describe('ProjectDetailsComponent', () => {
let component: ProjectDetailsComponent;
let fixture: ComponentFixture<ProjectDetailsComponent>;
let activatedRoute: ActivatedRouteStub;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([{ path: 'projects/:projectId', component: ProjectDetailsComponent }])],
declarations: [ProjectDetailsComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [{ provide: ProjectsService, useClass: ProjectsServiceStub }, {provide: ActivatedRoute, useClass: ActivatedRouteStub}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectDetailsComponent);
component = fixture.componentInstance;
activatedRoute = fixture.debugElement.injector.get(ActivatedRoute);
activatedRoute.testParams = { projectId: '123'};
fixture.detectChanges();
});
fit('should create', () => {
expect(component).toBeTruthy();
});
});
params 未定义的唯一方法是您没有正确创建存根。看调用
this.route.parent.params.switchMap
params
是嵌套的 属性 两层。因此,作为普通的 JS 对象,您需要
let mock = {
parent: {
params: Observable.of(...)
}
}
如果你想使用 classes,你可以使用
class ActivatedRouteStub {
parent = {
params: Observable.of({})
};
set testParams(params: any) {
this.parent.params = Observable.of(params);
}
}
您只需在 testParams
上使用 setter 来设置 parent.params
的值。因此,当您执行 stub.testParams = whatever
时,该值将设置在 parent.params
.
的可观察对象上
更新
除了上面关于如何实现这个的解释,你的配置也有错误
{provide: ActivatedRoute, useValue: ActivatedRouteStub}
useValue
应该是您创建的对象。因此,您传递的是 class,而 class 将是注入的内容,而不是 class 的 实例 。如果你想 Angular 创建它,那么你应该使用 useClass
。否则你应该自己创建实例,并将该实例用作值
{provide: ActivatedRoute, useValue: new ActivatedRouteStub() }
注意实例化。
如果有人在使用 Angular 7 时遇到这个问题,Angular 文档给出了一个清晰的示例,说明如何测试依赖于 ActivatedRoute 服务的组件。参见:https://v7.angular.io/guide/testing#activatedroutestub。只是和上面的回答有点不同。
假设我想简单地对一个组件进行单元测试,该组件采用从部分路由获取的参数。例如,我的组件的 ngOnInit 看起来像这样:
ngOnInit() {
this.route.parent.params.switchMap((params: Params) => this.service.getProject(params['projectId']))
.subscribe((project: Project) => this.update(project));
}
我现在如何: 1:设置我的测试,以便组件创建完全有效,这样我就可以对其他部分进行单元测试
使用答案进行编辑 - 示例 ActivatedRouteStub 应该使用也具有可观察参数的父对象进行扩展,我应该使用 useClass 而不是 useValue(忘记改回去):
@Injectable()
export class ActivatedRouteStub {
// ActivatedRoute.params is Observable
private subject = new BehaviorSubject(this.testParams);
params = this.subject.asObservable();
// Test parameters
private _testParams: {};
get testParams() { return this._testParams; }
set testParams(params: {}) {
this._testParams = params;
this.subject.next(params);
}
// ActivatedRoute.snapshot.params
get snapshot() {
return { params: this.testParams };
}
// ActivatedRoute.parent.params
get parent() {
return { params: this.subject.asObservable() };
}
}
2: 在我的单元测试中为 projectId 提供一个值?
angular2 文档中的示例似乎不适用于 switchMap,甚至根本不起作用(我从那里使用了 ActivatedRouteStub,但到目前为止运气不好 - params 始终未定义)。
编辑答案:
describe('ProjectDetailsComponent', () => {
let component: ProjectDetailsComponent;
let fixture: ComponentFixture<ProjectDetailsComponent>;
let activatedRoute: ActivatedRouteStub;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes([{ path: 'projects/:projectId', component: ProjectDetailsComponent }])],
declarations: [ProjectDetailsComponent],
schemas: [NO_ERRORS_SCHEMA],
providers: [{ provide: ProjectsService, useClass: ProjectsServiceStub }, {provide: ActivatedRoute, useClass: ActivatedRouteStub}]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ProjectDetailsComponent);
component = fixture.componentInstance;
activatedRoute = fixture.debugElement.injector.get(ActivatedRoute);
activatedRoute.testParams = { projectId: '123'};
fixture.detectChanges();
});
fit('should create', () => {
expect(component).toBeTruthy();
});
});
params 未定义的唯一方法是您没有正确创建存根。看调用
this.route.parent.params.switchMap
params
是嵌套的 属性 两层。因此,作为普通的 JS 对象,您需要
let mock = {
parent: {
params: Observable.of(...)
}
}
如果你想使用 classes,你可以使用
class ActivatedRouteStub {
parent = {
params: Observable.of({})
};
set testParams(params: any) {
this.parent.params = Observable.of(params);
}
}
您只需在 testParams
上使用 setter 来设置 parent.params
的值。因此,当您执行 stub.testParams = whatever
时,该值将设置在 parent.params
.
更新
除了上面关于如何实现这个的解释,你的配置也有错误
{provide: ActivatedRoute, useValue: ActivatedRouteStub}
useValue
应该是您创建的对象。因此,您传递的是 class,而 class 将是注入的内容,而不是 class 的 实例 。如果你想 Angular 创建它,那么你应该使用 useClass
。否则你应该自己创建实例,并将该实例用作值
{provide: ActivatedRoute, useValue: new ActivatedRouteStub() }
注意实例化。
如果有人在使用 Angular 7 时遇到这个问题,Angular 文档给出了一个清晰的示例,说明如何测试依赖于 ActivatedRoute 服务的组件。参见:https://v7.angular.io/guide/testing#activatedroutestub。只是和上面的回答有点不同。