如何在 angular 组件内提供/模拟 Angularfirestore 模块以通过默认测试? [英] How to provide/mock Angularfirestore module inside angular component for default test to pass?

查看:22
本文介绍了如何在 angular 组件内提供/模拟 Angularfirestore 模块以通过默认测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在我的 app.component 中提供 AngularFirestore 模块,以便我的默认 toBeTruthy() 测试通过?

How can I provide AngularFirestore module inside my app.component so that my default toBeTruthy() test will pass?

Error: StaticInjectorError(DynamicTestModule)[AppComponent -> AngularFirestore]: 
      StaticInjectorError(Platform: core)[AppComponent -> AngularFirestore]: 
        NullInjectorError: No provider for AngularFirestore!

app.component

export class AppComponent implements OnInit {
  private notesCollection: AngularFirestoreCollection<any>;
  public notes: Observable<any[]>;

  constructor(private afs: AngularFirestore) {}

  ngOnInit() {
    this.notesCollection = this.afs.collection('notes');
    this.notes = this.notesCollection.valueChanges();
  }
}

这只是默认测试:

class FirebaseMock implements AngularFirestore {
  app: FirebaseApp;
  firestore: FirebaseFirestore;
  persistenceEnabled$: Observable<boolean>;

  collection<T>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<T> {
    return undefined;
  }

  doc<T>(path: string): AngularFirestoreDocument<T> {
    return undefined;
  }

  createId(): string {
    return undefined;
  }
}

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(
    async(() => {
      TestBed.configureTestingModule({
        imports: [
          RouterTestingModule,

        ],
        declarations: [ AppComponent ],
        providers: [
          {
            provide: AngularFirestoreModule,
            useClass: FirebaseMock
          },
        ],
      }).compileComponents();
    }),
  );

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

推荐答案

您必须模拟AngularFirestore"或按原样注入它并对其方法创建间谍,以免它被调用.我不会推荐第二个选项,因为它需要注入真正的服务,这也可能依赖于其他服务.因此,您还必须注入它们,这可能最终需要数百万个服务来测试一个组件.所以,让我们选择第一个选项.

You have to either mock "AngularFirestore" or inject it as is and create spy on its methods so it won't get called. I would not recommend the second option because it requires the real service to be injected which may depend on other services too. So, you have to inject them as well which may end up requiring millions of services to test just one component. So, let's go with the first option.

如果它在您的组件中常用,我建议您为这些类型的服务创建一个存根"模块,并将此模块导入到您要测试的组件测试模块中.如果只是为了这个组件,你可以像这样创建一个简单的东西:(让我们从简单的开始,然后创建模块)

If it is commonly used among your component, I'd suggest you create a "stub" module for these kinds of services and import this module in components test modules that you want to test. If it is just for this component, you can create something easy like this: (let's start with easy one and create module later)

app.component.spec.ts

describe('AppComponent', () => {
    let component: AppComponent;
    let fixture: ComponentFixture<AppComponent>;

    const AngularFirestoreStub = {
        // I just mocked the function you need, if there are more, you can add them here.
        collection: (someString) => {
            // return mocked collection here
        }
    };

    beforeEach(
        async(() => {
           TestBed.configureTestingModule({
               imports: [ RouterTestingModule],
               // I used 'useValue' because it is just a json. If it was class, I'd use 'useClass'
               providers: [{provide: AngularFirestore, useValue: AngularFirestoreStub}]
               declarations: [ AppComponent ]
           }).compileComponents();
        })
    );

    beforeEach(() => {
        fixture = TestBed.createComponent(AppComponent); // Should be fine
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy(); // Should pass
    });
});

正如我之前所说,如果 AngularFirestore 是您的许多组件都使用的服务,那么在您的项目中的某处创建一个存根模块(在我的项目中,我创建了一个 testing> 文件夹并将其放在 src)

As I said before, if AngularFirestore is a service used by many of your components, then create a stub module somewhere in your project (in my project I created a testing folder and put it next to src)

CommonServiceModuleStub

@NgModule({
    providers: [{provide: AngularFirestore, useClass: AngularFirestoreStub}]
})
export class CommonServiceModuleStub {}

// I'd recommend you put this service in a subfolder.
// This time, I created a class instead of a json. 
// It is because, your other components may require more 'mocked' functions.
// It may be harder to maintain them within a json.
@Injectable()
export class AngularFirestoreStub {
    collection(someString) {
        // return mock collection;
    }
}

现在,不要提供自己,只需导入我们刚刚创建的模块

Now, instead of providing yourself just import the module we just created

app.component.spec.ts

 ...
 TestBed.configureTestingModule({
     imports: [ RouterTestingModule, CommonServiceModuleStub],
     declarations: [ AppComponent ]
 }).compileComponents();

选项 2

有时,您的服务很简单,您不想费心去模拟"它们.看下面的例子

Sometimes, your services are simple ones and you don't want to bother going all the way to "mock" them. Take a look at the following example

app.component.ts

@Component({ ... })
export class AppComponent {
    constructor(private myService: AwesomeService) {}

    doSomethingCool() {
        this.myService.getAwesomeStuff();
    }
}

我们先配置TestBed

app.component.spec.ts

 ...
 TestBed.configureTestingModule({
     imports: [ RouterTestingModule],
     // since, 'AwesomeService' is a service on its own and 
     // doesn't require other services, we easily provide it here
     providers: [ AwesomeService ]
     declarations: [ AppComponent ]
 }).compileComponents();

在测试中

it('should do something cool without getting awesome stuff', () => {
    spyOn(component.myService, 'getAwesomeStuff');
    // Note: if you want to spy on it and you want it to get called for real
    // you should do following
    // spyOn(component.myService, 'getAwesomeStuff').and.callThrough();
    // or return fake output
    // spyOn(component.myService, 'getAwesomeStuff')
    //        .and.callFake((arguments, can, be, received) =>  {
    //                          return fake;
    //                      });

    component.doSomethingCool();
    expect(component.myService.getAwesomeStuff).toHaveBeenCalled();
});

有关更多信息,您可以查看 jasmine 文档

For more info, you can take a look at jasmine docs

这篇关于如何在 angular 组件内提供/模拟 Angularfirestore 模块以通过默认测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆