angular - 通过 spy /karma 模拟服务类时无法读取未定义的属性 'doc'

标签 angular firebase testing karma-jasmine spy

我正在尝试通过 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 方法。有谁知道我应该在 getSprints() 方法中返回或生成什么以使我的 ngOnInit 再次工作?帮助将不胜感激。

最佳答案

我看到您正在动态测试模块中导入和初始化 AngularFireModule。这意味着每次运行测试时它实际上都连接到 firebase 后端。这通常是一个非常糟糕的主意。如果您的测试用例需要测试编辑或删除条目怎么办?这意味着他们每次都会根据实际数据进行操作。

理想情况下,您希望模拟所有依赖项并尽可能避免导入真实的依赖项(我知道在 Angular 世界中这并不总是可能的)。

我为自己找到的一个解决方案是使用 ts-mockito图书馆。它允许您轻松地模拟类,它通常开箱即用。我前段时间写了一篇博文,如果您想了解更多信息:Mocking with ts-mockito

...

回到你的具体例子。看起来您的模拟数据形状与 firebase 服务返回的不匹配。

      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 中,您返回一个带有形状的项目数组的可观察对象:

{
  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})
    }
  }
}]

关于angular - 通过 spy /karma 模拟服务类时无法读取未定义的属性 'doc',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56355984/

相关文章:

angular - 如何将依赖项传递给@auth0-angular-jwt?

javascript - 将括号内的字符串传递给另一个字符串

android - Firebase - Android - fetchProvidersForEmail - 为什么所有调用都是异步的?

angular - 在 Angular 中将异步数据从父级传递给子级

ruby-on-rails - Ruby on Rails - 访问 :has_many => :through association 中的数据

javascript - 如何在 Angular http 拦截器中以异步方式缓存 http 请求?

html - Angular 有效地使用 trackBy 和 ngFor

c# - 我使用 Firebase 的统一登录不起作用

android - 从 Firebase Analytics 日志记录中排除测试设备

java - JUnit 测试在 setUp 中崩溃