通过 spy/karma 模拟服务 class 时无法读取未定义的 属性 'doc'
Cannot read property 'doc' of undefined when mocking service class through spy/karma
我正在尝试通过 Karma 测试我的 angular 应用程序。我的应用程序连接到 firebase firestore 数据库。我正在尝试模拟一个集合并使用它来测试我的组件功能。
我使用的代码片段如下:
sprint.service.ts:
export class SprintService {
getSprints() {
return this.firestore.collection('sprints').snapshotChanges();
}
constructor(private firestore: AngularFirestore) { }
}
sprints.component.ts
sprints : Sprint[];
constructor(private sprintService: SprintService) { }
ngOnInit() {
this.sprintService.getSprints().subscribe(data => {
this.sprints = data.map(e => {
return {
id: e.payload.doc.id, //HERE IT ERRORS
...e.payload.doc.data()
} as Sprint;
})
});
}
sprints.component.spec.ts
//Mock class
class MockSprintServce
{
getSprints(){
return of([
{id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
{id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
])
}
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ FormsModule, AngularFireModule.initializeApp(environment.firebase) ],
declarations: [ ArchivedUserstoriesComponent,SprintDetailComponent, SprintsComponent, UserDetailComponent, UsersComponent, UserstoriesComponent, UserstoryDetailComponent ],
providers: [AngularFirestore, {provide: SprintService, useClass: MockSprintServce}]
})
.compileComponents();
}));
beforeEach(() => {
app.sprints = [
{id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
{id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
]
});
it(`should return all Sprints`, async(() => {
//arrange
let getSpy = spyOn(mockSprintServiceObject, 'getSprints').and.returnValue({ subscribe: () => {} });
//act
app.ngOnInit({});
//assert
expect(getSpy).toHaveBeenCalled();
expect(getSpy).toContain(app.sprints[1]);
}));
我希望代码能够正常运行,没有任何错误。我可能认为我必须重写 MockSprintService 中的 getSprints
方法。有谁知道我应该 return 或在 getSprints()
方法中生成什么以使我的 ngOnInit 再次工作?帮助将不胜感激。
在模拟的 getSprints() 方法中,您应该 return 具有以下结构的对象数组:
{ payload: { doc: { id: some_id }} }
因为现在您 e.payload 在您的模拟数组中未定义。
我看到您在动态测试模块中导入和初始化 AngularFireModule。这意味着每次 运行 测试时它实际上都连接到 firebase 后端。这通常是一个非常糟糕的主意。如果您的测试用例需要测试编辑或删除条目怎么办?这意味着他们每次都会根据实际数据进行操作。
理想情况下,您希望模拟所有依赖项并尽可能避免导入真实的依赖项(我知道在 Angular 世界中这并不总是可能的)。
我为自己找到的一个解决方案是使用 ts-mockito library. It allows you to mock classes with ease it often it works out of the box. There's a blog post I wrote some time ago, if you'd like to learn more: Mocking with ts-mockito
...
回到你的具体例子。看起来您的模拟数据形状与 firebase 服务不匹配 returns.
this.sprints = data.map(e => {
return {
id: e.payload.doc.id, //HERE IT ERRORS
...e.payload.doc.data()
} as Sprint;
})
你映射每个数据项,它应该有一个 payload
对象和 doc
对象,它有 id
属性 和 data()
方法.
但是,在您的 MockSprintServce 中,您 return 一个具有以下形状的项目数组的可观察对象:
{
id: "1",
name:"TestSprint",
description:"TestSprint",
startDate:new Date(2000, 0, 1),
endDate:new Date(2001, 0, 1),
isActive:true
}
根本就是不匹配。
如果您想继续当前的设置并使其正常工作,请尝试更改
中的项目
getSprints(){
return of(...
到
[{
payload: {
doc: {
id: '1',
data: () => ({id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true})
}
}
}]
我正在尝试通过 Karma 测试我的 angular 应用程序。我的应用程序连接到 firebase firestore 数据库。我正在尝试模拟一个集合并使用它来测试我的组件功能。
我使用的代码片段如下:
sprint.service.ts:
export class SprintService {
getSprints() {
return this.firestore.collection('sprints').snapshotChanges();
}
constructor(private firestore: AngularFirestore) { }
}
sprints.component.ts
sprints : Sprint[];
constructor(private sprintService: SprintService) { }
ngOnInit() {
this.sprintService.getSprints().subscribe(data => {
this.sprints = data.map(e => {
return {
id: e.payload.doc.id, //HERE IT ERRORS
...e.payload.doc.data()
} as Sprint;
})
});
}
sprints.component.spec.ts
//Mock class
class MockSprintServce
{
getSprints(){
return of([
{id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
{id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
])
}
}
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ FormsModule, AngularFireModule.initializeApp(environment.firebase) ],
declarations: [ ArchivedUserstoriesComponent,SprintDetailComponent, SprintsComponent, UserDetailComponent, UsersComponent, UserstoriesComponent, UserstoryDetailComponent ],
providers: [AngularFirestore, {provide: SprintService, useClass: MockSprintServce}]
})
.compileComponents();
}));
beforeEach(() => {
app.sprints = [
{id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true},
{id: "2", name:"TestSprint2", description:"TestSprint2", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:false},
]
});
it(`should return all Sprints`, async(() => {
//arrange
let getSpy = spyOn(mockSprintServiceObject, 'getSprints').and.returnValue({ subscribe: () => {} });
//act
app.ngOnInit({});
//assert
expect(getSpy).toHaveBeenCalled();
expect(getSpy).toContain(app.sprints[1]);
}));
我希望代码能够正常运行,没有任何错误。我可能认为我必须重写 MockSprintService 中的 getSprints
方法。有谁知道我应该 return 或在 getSprints()
方法中生成什么以使我的 ngOnInit 再次工作?帮助将不胜感激。
在模拟的 getSprints() 方法中,您应该 return 具有以下结构的对象数组:
{ payload: { doc: { id: some_id }} }
因为现在您 e.payload 在您的模拟数组中未定义。
我看到您在动态测试模块中导入和初始化 AngularFireModule。这意味着每次 运行 测试时它实际上都连接到 firebase 后端。这通常是一个非常糟糕的主意。如果您的测试用例需要测试编辑或删除条目怎么办?这意味着他们每次都会根据实际数据进行操作。
理想情况下,您希望模拟所有依赖项并尽可能避免导入真实的依赖项(我知道在 Angular 世界中这并不总是可能的)。
我为自己找到的一个解决方案是使用 ts-mockito library. It allows you to mock classes with ease it often it works out of the box. There's a blog post I wrote some time ago, if you'd like to learn more: Mocking with ts-mockito
...
回到你的具体例子。看起来您的模拟数据形状与 firebase 服务不匹配 returns.
this.sprints = data.map(e => {
return {
id: e.payload.doc.id, //HERE IT ERRORS
...e.payload.doc.data()
} as Sprint;
})
你映射每个数据项,它应该有一个 payload
对象和 doc
对象,它有 id
属性 和 data()
方法.
但是,在您的 MockSprintServce 中,您 return 一个具有以下形状的项目数组的可观察对象:
{
id: "1",
name:"TestSprint",
description:"TestSprint",
startDate:new Date(2000, 0, 1),
endDate:new Date(2001, 0, 1),
isActive:true
}
根本就是不匹配。 如果您想继续当前的设置并使其正常工作,请尝试更改
中的项目 getSprints(){
return of(...
到
[{
payload: {
doc: {
id: '1',
data: () => ({id: "1", name:"TestSprint", description:"TestSprint", startDate:new Date(2000, 0, 1), endDate:new Date(2001, 0, 1), isActive:true})
}
}
}]