在 Angular 应用中,路由对整个应用的用户体验,起着非常重要的作用。因此,对路由进行单元测试,可以确保应用的正确和高效运行。
路由的单元测试工作,主要包括以下三个方面:
- 测试导航地址是否正确
- 测试路由参数是否正确
- 测试加载组件是否正确
测试导航地址
在 Angular 应用中,通过在 a
元素上添加 routerLink 指令,实现路由功能。
在测试前,我们需要建立一个指令的 stub
,避免做大量的工作去建立完整的 routerLink
.
import { Directive, Input } from "@angular/core”;
@Directive({
selector: '[routerLink]’
})
export class RouterLinkDirectiveStub {
@Input('routerLink') linkParams: any;
}
在这里,selector
必须匹配 routerLink
指令,才能正常工作。我们会使用 routerLink
绑定,实现真实的 routerLink
指令的行为。这样,routerLink
指令的 linkParams
属性会把导航地址传递给 stub
.
现在可以编写测试:
it('should set up routerLink directives', () => {
const linkDe = fixture.debugElement.queryAll(By.directive(RouterLinkDirectiveStub));
const links = linkDe.map(de => de.injector.get(RouterLinkDirectiveStub));
expect(links.length).toBe(2);
expect(links[0].linkParams).toEqual('home’);
expect(links[1].linkParams).toEqual(['heroes', 1]);
});
it('should get the id parameter', () => {
expect(component.heroId).toBe(1);
});
在测试用例中,我们使用 By
工具类的 directive
方法,指定查询元件的类型:组件或指令。 debugElement
属性的 queryAll
方法,返回了所有查询到的 routerLink
指令。然后,就可以对指令的数量,链接参数进行测试。
测试路由参数
- 调整提供导航的组件:
@Component({
selector: 'app-menu’,
templateUrl: './menu.component.html’,
styleUrls: ['./menu.component.css’]
})
export class MenuComponent implements OnInit {
bookId: number;
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.route.paramMap.subscribe(params => this.bookId = + params.get('id’));
}
}
在初始化函数中,对 paramMap
方法进行订阅,获得参数 id
对值。
- 创建一个
stub
,模拟paramMap
方法的行为:
export class ActivatedRouteStub {
private subject = new ReplaySubject<ParamMap>();
constructor(initialParams?: Params) {
this.setParamMap(initialParams);
}
readonly paramMap = this.subject.asObservable();
setParamMap(params?: Params) {
this.subject.next(convertToParamMap(params));
}
}
在这里,可以使用 constructor
构造函数或 setParamMap
设置路由参数。
- 编写单元测试:
…
beforeEach(() => {
const activatedRoute = new ActivatedRouteStub();
activatedRoute.setParamMap({id: 1});
TestBed.configureTestingModule({
declarations: [
MenuComponent,
RouterLinkDirectiveStub,
RouterOutletComponentStub
],
providers: [
{ provide: ActivatedRoute, useValue: activatedRoute }
],
})
.compileComponents();
});
...
it('should get the id parameter', () => {
expect(component.bookId).toBe(1);
});
首先,在测试初始化阶段,创建了 ActivatedRouteStub
类的一个实例,并设置参数 id 的值为 1. 然后,在配置测试模块时,把 activatedRoute
作为提供者进行添加。最后,我们验证组件的属性是否正确接收了来自路由参数的值。
测试加载组件
Angular 为我们提供了一个测试真实路由功能的类 RouterTestingModule
,可以定义我们在测试时需要的路由:
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([{
path: 'heroes/:id’,
component: MenuComponent
}])
],
declarations: [MenuComponent]
});
通过使用这个方法,不仅可以测试路由的导航地址和路由参数,也可以测试是否正确加载组件。
为了测试加载组件,需要创建一个组件的 stub
,提供 router-outlet
,作为组件加载的占位符。
@Component({
selector: 'router-outlet’,
template: ‘'
})
export class RouterOutletComponentStub { }
最后,在配置测试模块的时候,可以为 schemas
属性添加 NO_ERRORS_SCHEMA
。这样,就不必再去创建一个目标组件,Angular 会忽略任何在模板中不能识别的组件。
网友评论