Angular 测试如何模拟 ActivatedRoute 数据
Angular test how to mock ActivatedRoute data
我在模拟 ActivatedRoute 数据时遇到了一个大问题 属性。无论我在做什么,它最终都会出现错误消息:Error: <spyOnProperty> : Property data does not have access type get
。将存根 const 移动到单独的模拟 class 也没有解决问题。我发现这应该是直截了当的,但我已经为此苦苦挣扎了几天。
组件
@Component({
selector: 'app-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.css']
})
export class NotificationsComponent implements OnInit {
notifications: NotificationEntry[];
constructor(
private route: ActivatedRoute,
private modalService: ModalService,
private messageBoxService: MessageBoxService,
private notificationsService: NotificationsService
) {}
ngOnInit() {
this.route.data.subscribe(
(data: { notifications: NotificationEntry[] }) => {
this.notifications = data.notifications;
}
);
}
}
Component.spec
describe('NotificationsComponent', () => {
let component: NotificationsComponent;
let fixture: ComponentFixture<NotificationsComponent>;
const registryVersionBasicData = new RegistryVersionBasicData(
false,
'versionId',
new JsonDate('Unspecified', 631894104000000000),
'user',
'comment'
)
const notifications = new NotificationEntry(
new JsonDate('Unspecified', 631894104000000000),
'summary',
'message',
NotificationEntityType.StressScenario,
'instance name',
'instance key',
registryVersionBasicData,
'additional information')
const notificationsArray = [notifications]
beforeEach(() => {
const activatedRouteStub = { data: of({ notifications: notificationsArray }) };
const modalServiceStub = {};
const messageBoxServiceStub = {};
const notificationsServiceStub = {};
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: ModalService, useValue: modalServiceStub },
{ provide: MessageBoxService, useValue: messageBoxServiceStub },
{ provide: NotificationsService, useValue: notificationsServiceStub },
]
}).compileComponents();
fixture = TestBed.createComponent(NotificationsComponent);
component = fixture.componentInstance;
});
it('can load instance', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should get notifications entry', () => {
const activatedRouteStub = TestBed.get(ActivatedRoute);
spyOnProperty(activatedRouteStub, 'data')
component.ngOnInit();
expect(component.notifications).toEqual(notificationsArray)
});
});
});
按如下方式定义您的 activatedRouteStub-
class ActivatedRouteStub {
private _data = new BehaviorSubject(notifications);
get data() {
return this._data;
}
set data(notifications: NotificationEntry[]) {
this.data.next(notifications)
}
}
然后在您的提供商中使用它作为
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub()}
现在您可以通过
更改数据
const activeRoute = testBed.get(ActivatedRoute);
activeRoute.data = [new Notification()];
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsComponent } from './notifications.component';
import { ActivatedRoute } from '@angular/router';
import { ModalService, MessageBoxService, NotificationsService, NotificationEntry, JsonDate, NotificationEntityType, RegistryVersionBasicData } from 'src/app/shared';
import { OrderPipe } from 'ngx-order-pipe';
import { RenderDatePipe } from 'src/app/shared/pipes/renderdate.pipe';
import { VersionInfoPipe } from 'src/app/shared/pipes/versioninfo.pipe';
import { of } from 'rxjs';
fdescribe('NotificationsComponent', () => {
let component: NotificationsComponent;
let fixture: ComponentFixture<NotificationsComponent>;
const registryVersionBasicData = new RegistryVersionBasicData(
false,
'versionId',
new JsonDate('Unspecified', 631894104000000000),
'user',
'comment'
);
const notifications = new NotificationEntry(
new JsonDate('Unspecified', 631894104000000000),
'summary',
'message',
NotificationEntityType.StressScenario,
'instance name',
'instance key',
registryVersionBasicData,
'additional information');
const route = { data: of({ notifications: [notifications] }) };
beforeEach(() => {
const modalServiceStub = {};
const messageBoxServiceStub = {};
const notificationsServiceStub = {};
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
providers: [
{ provide: ActivatedRoute, useValue: route },
{ provide: ModalService, useValue: modalServiceStub },
{ provide: MessageBoxService, useValue: messageBoxServiceStub },
{ provide: NotificationsService, useValue: notificationsServiceStub },
]
});
fixture = TestBed.createComponent(NotificationsComponent);
component = fixture.componentInstance;
});
it('can load instance', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should get notifications entry', () => {
component.ngOnInit();
expect(component.notifications).toEqual([notifications]);
});
});
});
最简单的可能解决方案。使用:
const route = { data: of({ notifications: [notifications] }) };
.. 然后,在组件提供者中使用这个值:
{ provide: ActivatedRoute, useValue: route }
.. 作为 ActivatedRoute 的原始模拟。然后,您的测试用例可能如下所示(不需要 TestBed):
describe('ngOnInit', () => {
it('should get notifications entry', () => {
component.ngOnInit();
expect(component.notifications).toEqual([notifications]);
});
});
我在模拟 ActivatedRoute 数据时遇到了一个大问题 属性。无论我在做什么,它最终都会出现错误消息:Error: <spyOnProperty> : Property data does not have access type get
。将存根 const 移动到单独的模拟 class 也没有解决问题。我发现这应该是直截了当的,但我已经为此苦苦挣扎了几天。
组件
@Component({
selector: 'app-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.css']
})
export class NotificationsComponent implements OnInit {
notifications: NotificationEntry[];
constructor(
private route: ActivatedRoute,
private modalService: ModalService,
private messageBoxService: MessageBoxService,
private notificationsService: NotificationsService
) {}
ngOnInit() {
this.route.data.subscribe(
(data: { notifications: NotificationEntry[] }) => {
this.notifications = data.notifications;
}
);
}
}
Component.spec
describe('NotificationsComponent', () => {
let component: NotificationsComponent;
let fixture: ComponentFixture<NotificationsComponent>;
const registryVersionBasicData = new RegistryVersionBasicData(
false,
'versionId',
new JsonDate('Unspecified', 631894104000000000),
'user',
'comment'
)
const notifications = new NotificationEntry(
new JsonDate('Unspecified', 631894104000000000),
'summary',
'message',
NotificationEntityType.StressScenario,
'instance name',
'instance key',
registryVersionBasicData,
'additional information')
const notificationsArray = [notifications]
beforeEach(() => {
const activatedRouteStub = { data: of({ notifications: notificationsArray }) };
const modalServiceStub = {};
const messageBoxServiceStub = {};
const notificationsServiceStub = {};
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
providers: [
{ provide: ActivatedRoute, useValue: activatedRouteStub },
{ provide: ModalService, useValue: modalServiceStub },
{ provide: MessageBoxService, useValue: messageBoxServiceStub },
{ provide: NotificationsService, useValue: notificationsServiceStub },
]
}).compileComponents();
fixture = TestBed.createComponent(NotificationsComponent);
component = fixture.componentInstance;
});
it('can load instance', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should get notifications entry', () => {
const activatedRouteStub = TestBed.get(ActivatedRoute);
spyOnProperty(activatedRouteStub, 'data')
component.ngOnInit();
expect(component.notifications).toEqual(notificationsArray)
});
});
});
按如下方式定义您的 activatedRouteStub-
class ActivatedRouteStub {
private _data = new BehaviorSubject(notifications);
get data() {
return this._data;
}
set data(notifications: NotificationEntry[]) {
this.data.next(notifications)
}
}
然后在您的提供商中使用它作为
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub()}
现在您可以通过
更改数据const activeRoute = testBed.get(ActivatedRoute);
activeRoute.data = [new Notification()];
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { NotificationsComponent } from './notifications.component';
import { ActivatedRoute } from '@angular/router';
import { ModalService, MessageBoxService, NotificationsService, NotificationEntry, JsonDate, NotificationEntityType, RegistryVersionBasicData } from 'src/app/shared';
import { OrderPipe } from 'ngx-order-pipe';
import { RenderDatePipe } from 'src/app/shared/pipes/renderdate.pipe';
import { VersionInfoPipe } from 'src/app/shared/pipes/versioninfo.pipe';
import { of } from 'rxjs';
fdescribe('NotificationsComponent', () => {
let component: NotificationsComponent;
let fixture: ComponentFixture<NotificationsComponent>;
const registryVersionBasicData = new RegistryVersionBasicData(
false,
'versionId',
new JsonDate('Unspecified', 631894104000000000),
'user',
'comment'
);
const notifications = new NotificationEntry(
new JsonDate('Unspecified', 631894104000000000),
'summary',
'message',
NotificationEntityType.StressScenario,
'instance name',
'instance key',
registryVersionBasicData,
'additional information');
const route = { data: of({ notifications: [notifications] }) };
beforeEach(() => {
const modalServiceStub = {};
const messageBoxServiceStub = {};
const notificationsServiceStub = {};
TestBed.configureTestingModule({
schemas: [NO_ERRORS_SCHEMA],
declarations: [NotificationsComponent, OrderPipe, RenderDatePipe, VersionInfoPipe],
providers: [
{ provide: ActivatedRoute, useValue: route },
{ provide: ModalService, useValue: modalServiceStub },
{ provide: MessageBoxService, useValue: messageBoxServiceStub },
{ provide: NotificationsService, useValue: notificationsServiceStub },
]
});
fixture = TestBed.createComponent(NotificationsComponent);
component = fixture.componentInstance;
});
it('can load instance', () => {
expect(component).toBeTruthy();
});
describe('ngOnInit', () => {
it('should get notifications entry', () => {
component.ngOnInit();
expect(component.notifications).toEqual([notifications]);
});
});
});
最简单的可能解决方案。使用:
const route = { data: of({ notifications: [notifications] }) };
.. 然后,在组件提供者中使用这个值:
{ provide: ActivatedRoute, useValue: route }
.. 作为 ActivatedRoute 的原始模拟。然后,您的测试用例可能如下所示(不需要 TestBed):
describe('ngOnInit', () => {
it('should get notifications entry', () => {
component.ngOnInit();
expect(component.notifications).toEqual([notifications]);
});
});