如何在单元测试中模拟 AngularFire 2 服务?
Posted
技术标签:
【中文标题】如何在单元测试中模拟 AngularFire 2 服务?【英文标题】:How to mock AngularFire 2 service in unit test? 【发布时间】:2016-10-28 19:36:47 【问题描述】:我正在尝试使用 AngularFire 2 auth 为示例 Angular 2 应用程序设置单元测试,该组件相当简单:
import Component from '@angular/core';
import AngularFire, AuthProviders from 'angularfire2';
@Component(
moduleId: module.id,
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css']
)
export class AppComponent
isLoggedIn: boolean;
constructor(public af: AngularFire)
this.af.auth.subscribe(auth =>
if (auth)
this.isLoggedIn = true;
else
this.isLoggedIn = false;
);
loginWithFacebook()
this.af.auth.login(
provider: AuthProviders.Facebook
);
logout()
this.af.auth.logout();
我所做的只是围绕 AngularFire 中的 login
和 logout
方法,所以我正在考虑使用模拟来检查是否调用了这些方法,但我不确定从哪里开始,我试着做我的规范文件中的以下内容:
import provide from '@angular/core';
import AngularFire from 'angularfire2';
import
beforeEach, beforeEachProviders,
describe, xdescribe,
expect, it, xit,
async, inject
from '@angular/core/testing';
import AppComponent from './app.component';
spyOn(AngularFire, 'auth');
beforeEachProviders(() => [
AppComponent,
AngularFire
]);
describe('App Component', () =>
it('should create the app',
inject([AppComponent], (app: AppComponent) =>
expect(app).toBeTruthy();
)
);
it('should log user in',
inject([AppComponent], (app: AppComponent) =>
expect(app.fb.auth.login).toHaveBeenCalled();
)
);
it('should log user out',
inject([AppComponent], (app: AppComponent) =>
expect(app.fb.auth.logout).toHaveBeenCalled();
)
);
);
但是我不确定如何模拟 login
和 logout
方法,因为它们是 auth
属性的一部分,有没有办法模拟 auth
以及返回的 login
和logout
方法?
【问题讨论】:
感兴趣的读者应该关注this issue,以减少这方面的痛苦。 【参考方案1】:在这个sn-p中:
beforeEach(() => addProviders([
AppComponent,
AngularFire
]);
您设置(或override)将在您的测试中使用的提供程序。
话虽如此,您可以创建一个不同的类,如果您愿意,可以创建一个模拟类,并使用 provide: originalClass, useClass: fakeClass
表示法提供它而不是AngularFire
实际类。
类似这样的:
class AngularFireAuthMock extends AngularFireAuth // added this class
public login() ...
public logout() ...
class AngularFireMock extends AngularFire // added this class
public auth: AngularFireAuthMock;
beforeEach(() => addProviders([
AppComponent,
provide: AngularFire, useClass: AngularFireMock // changed this line
]);
您测试中的AngularFire
s 将是AngularFireMock
s。
【讨论】:
【参考方案2】:希望这不是主题,但我找到了如何模拟 FirebaseDatabase 的最简单的解决方案。
var object = function()
var obj = valueChanges()
return of(data:'data');
return obj;
providers: [..., provide : AngularFireDatabase,
useValue: object : object ]
代替 data:'data' 你可以模拟你需要的任何数据。功能可以随意修改。
【讨论】:
【参考方案3】:类似于@jan,我使用一些实用函数做了一个模拟:
import AngularFireAuth from '@angular/fire/auth';
import AngularFireDatabase from '@angular/fire/database';
import auth from 'firebase/app';
import Observable, of, Subscription from 'rxjs';
/**
* Mocks the Firebase auth by automatically logging in.
*/
export const AngularFireAuthMock = jasmine.createSpy('signInWithEmailAndPassword')
.and.returnValue(Promise.resolve(uid: 'fakeuser'));
/**
* Mocks an AngularFireDatabase that always returns the given data for any path.
*/
export function mockAngularFireDatabase(data): AngularFireDatabase
return
object: (path: string): any =>
return
valueChanges()
return of(data);
as AngularFireDatabase;
然后你可以像这样在你的规范中使用它们:
beforeEach(async () =>
await TestBed.configureTestingModule(
declarations: [ TweakComponent ],
imports: [ MatDialogModule, RouterTestingModule ],
providers: [
provide: MAT_DIALOG_DATA, useValue: ,
provide: AngularFireDatabase, useValue: mockAngularFireDatabase(testdata:'hi'),
provide: AngularFireAuth, useValue: AngularFireAuthMock
],
)
.compileComponents();
);
【讨论】:
以上是关于如何在单元测试中模拟 AngularFire 2 服务?的主要内容,如果未能解决你的问题,请参考以下文章
Angular 2:如何在单元测试时模拟 ChangeDetectorRef
Angular 2 单元测试组件,模拟 ContentChildren