如何在单元测试中模拟 AngularFire 2 服务?
How to mock AngularFire 2 service in unit test?
我正在尝试使用 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
属性 的一部分,有没有办法mock auth
以及返回的 login
和 logout
方法?
在此代码段中:
beforeEach(() => addProviders([
AppComponent,
AngularFire
]);
您设置(或override)将在您的测试中使用的提供程序。
也就是说,您可以创建一个不同的 class,如果您愿意,可以创建一个模拟,并使用 { provide: originalClass, useClass: fakeClass }
符号提供它而不是 AngularFire
实际 class.
像这样:
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
将是 AngularFireMock
。
希望这不是题外话,但这是我找到的最简单的解决方案,如何模拟 FirebaseDatabase。
var object = function() {
var obj = { valueChanges() {
return of({data:'data'});
}
}
return obj;
}
providers: [..., { provide : AngularFireDatabase,
useValue: {object : object }} ]
而不是数据:'data' 你可以模拟你需要的任何数据。功能可以随意修改
类似于@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 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
属性 的一部分,有没有办法mock auth
以及返回的 login
和 logout
方法?
在此代码段中:
beforeEach(() => addProviders([
AppComponent,
AngularFire
]);
您设置(或override)将在您的测试中使用的提供程序。
也就是说,您可以创建一个不同的 class,如果您愿意,可以创建一个模拟,并使用 { provide: originalClass, useClass: fakeClass }
符号提供它而不是 AngularFire
实际 class.
像这样:
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
将是 AngularFireMock
。
希望这不是题外话,但这是我找到的最简单的解决方案,如何模拟 FirebaseDatabase。
var object = function() {
var obj = { valueChanges() {
return of({data:'data'});
}
}
return obj;
}
providers: [..., { provide : AngularFireDatabase,
useValue: {object : object }} ]
而不是数据:'data' 你可以模拟你需要的任何数据。功能可以随意修改
类似于@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();
});