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

查看:58
本文介绍了如何在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!

应用组件

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();
});

有关更多信息,您可以查看茉莉花文档

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

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

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