我正在测试用于编辑对象的组件。该对象具有唯一的id
,用于从服务中托管的对象数组中获取特定对象。特定id
是通过路由传递的参数获得的,特别是通过ActivatedRoute
类传递的参数。
构造函数如下:
constructor(private _router:Router, private _curRoute:ActivatedRoute, private _session:Session) {
}
ngOnInit() {
this._curRoute.params.subscribe(params => {
this.userId = params['id'];
this.userObj = this._session.allUsers.filter(user => user.id.toString() === this.userId.toString())[0];
我想对此组件运行基本单元测试。但是,我不确定如何注入id
参数,组件需要此参数。
顺便说一句:我已经有了Session
服务的模拟,所以不用担心。
答案 0 :(得分:89)
最简单的方法是使用useValue
属性并提供要模拟的值的Observable。
{
provide: ActivatedRoute,
useValue: {
params: Observable.of({id: 123})
}
}
答案 1 :(得分:16)
我已经想出了如何做到这一点!
由于ActivatedRoute
是一项服务,因此可以为其建立模拟服务。我们称之为模拟服务MockActivatedRoute
。我们会在ActivatedRoute
中扩展MockActivatedRoute
,如下所示:
class MockActivatedRoute extends ActivatedRoute {
constructor() {
super(null, null, null, null, null);
this.params = Observable.of({id: "5"});
}
行super(null, ....)
初始化超类,它有四个必需参数。但是,在这种情况下,我们不需要任何这些参数,因此我们将它们初始化为null
值。我们所需要的只是params
的值Observable<>
。因此,对于this.params
,我们会覆盖params
的值,并将其初始化为测试主题所依赖的参数的Observable<>
。
然后,与任何其他模拟服务一样,只需初始化它并覆盖组件的提供者。
祝你好运!
答案 2 :(得分:8)
以下是我在最新的角度2.0中测试它的方法......
import { ActivatedRoute, Data } from '@angular/router';
和提供者部分
{
provide: ActivatedRoute,
useValue: {
data: {
subscribe: (fn: (value: Data) => void) => fn({
yourData: 'yolo'
})
}
}
}
答案 3 :(得分:3)
只需添加ActivatedRoute的模拟:
unset PYTHON_INSTALL_LAYOUT
/root/.local/share/letsencrypt/bin/pip install --upgrade certbot
...
providers: [
{ provide: ActivatedRoute, useClass: MockActivatedRoute }
]
答案 4 :(得分:2)
对于从事Angular> 5的某些人, if Observable.of();无法正常工作,那么他们可以通过从'rxjs'导入import {of}来仅使用of();
答案 5 :(得分:1)
在为路由路径创建测试套件时遇到以下相同问题:
{
path: 'edit/:property/:someId',
component: YourComponent,
resolve: {
yourResolvedValue: YourResolver
}
}
在组件中,我将传递的属性初始化为:
ngOnInit(): void {
this.property = this.activatedRoute.snapshot.params.property;
...
}
在运行测试时,如果未在模拟的ActivatedRoute“ useValue”中传递属性值,则在使用“ fixture.detectChanges()”检测更改时,您将变得不确定。这是因为ActivatedRoute的模拟值不包含属性params.property。然后,需要模拟useValue具有这些参数,以便灯具在组件中初始化“ this.property”。您可以将其添加为:
let fixture: ComponentFixture<YourComponent>;
let component: YourComponent;
let activatedRoute: ActivatedRoute;
beforeEach(done => {
TestBed.configureTestingModule({
declarations: [YourComponent],
imports: [ YourImportedModules ],
providers: [
YourRequiredServices,
{
provide: ActivatedRoute,
useValue: {
snapshot: {
params: {
property: 'yourProperty',
someId: someId
},
data: {
yourResolvedValue: { data: mockResolvedData() }
}
}
}
}
]
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(YourComponent);
component = fixture.debugElement.componentInstance;
activatedRoute = TestBed.get(ActivatedRoute);
fixture.detectChanges();
done();
});
});
您可以开始进行测试,例如:
it('should ensure property param is yourProperty', async () => {
expect(activatedRoute.snapshot.params.property).toEqual('yourProperty');
....
});
现在,假设您要测试其他属性值,然后可以将模拟的ActivatedRoute更新为:
it('should ensure property param is newProperty', async () => {
activatedRoute.snapshot.params.property = 'newProperty';
fixture = TestBed.createComponent(YourComponent);
component = fixture.debugElement.componentInstance;
activatedRoute = TestBed.get(ActivatedRoute);
fixture.detectChanges();
expect(activatedRoute.snapshot.params.property).toEqual('newProperty');
});
希望这会有所帮助!
答案 6 :(得分:0)
在angular 8+中有一个RouterTestingModule,您可以使用它来访问组件的ActivatedRoute或Router。您也可以将路由传递到RouterTestingModule并为请求的路由方法创建间谍。
例如,在我的组件中,我有:
ngOnInit() {
if (this.route.snapshot.paramMap.get('id')) this.editMode()
this.titleService.setTitle(`${this.pageTitle} | ${TAB_SUFFIX}`)
}
在我的测试中,我有:
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ProductLinePageComponent ],
schemas: [NO_ERRORS_SCHEMA],
imports: [
RouterTestingModule.withRoutes([])
],
})
.compileComponents()
}))
beforeEach(() => {
router = TestBed.get(Router)
route = TestBed.get(ActivatedRoute)
})
以及稍后在“ it”部分:
it('should update', () => {
const spyRoute = spyOn(route.snapshot.paramMap, 'get')
spyRoute.and.returnValue('21')
fixture = TestBed.createComponent(ProductLinePageComponent)
component = fixture.componentInstance
fixture.detectChanges()
expect(component).toBeTruthy()
expect(component.pageTitle).toBe('Edit Product Line')
expect(component.formTitle).toBe('Edit Product Line')
// here you can test the functionality which is triggered by the snapshot
})
以类似的方式,我认为您可以通过返回可观察的结果或使用rxjs大理石通过茉莉花的spyOnProperty方法直接测试paramMap。这样可以节省一些时间,也不需要维护额外的模拟类。 希望它有用并且有意义。
答案 7 :(得分:0)
在测试类中将提供者添加为:
Platform
答案 8 :(得分:0)
到目前为止,所有其他答案都只提供了路由参数的值。如果您想测试路由更改触发器本身怎么办?您可以在测试中为 ActivatedRoute 提供 Subject 及其 Observable,以便您可以使用 source.next() 触发路由更改。
被测代码:
constructor(private readonly route: ActivatedRoute) {}
ngOnInit(): void {
this.routeParamSubscription = this.route.params.subscribe((params) => {
if (params['id']) {
this.loadDetails(params['id']);
}
});
}
测试代码:
let routeChangeSource: BehaviorSubject<Params>;
// In TestBed.configureTestingMethod
...
providers: [
{
provide: ActivatedRoute,
useValue: {
params: routeChangeSource.asObservable()
}
}
]
...
it('loads data on route change', fakeAsync(() => {
const spy = spyOn(component, 'loadDetails').and.callThrough();
routeChangeSource.next({ id: 99 });
tick();
expect(spy).toHaveBeenCalledOnceWith(99);
}));
这会在路由更改后测试触发的操作并确保它被激活。