[英]How to test an Angular Service using AngularFireDatabase with Jasmine Spy/Mock
我正在尝试测试我的数据服务,我可以使用真实服务(AngularFireDatabase)来测试,但我无法让模拟版本用于测试。
My DataStorage class 用于结合本地存储、远程存储等功能。 这使我们的应用程序可以轻松更改我们集成到的服务。
因此,我们有一些扩展的基本结构,例如 IDataRecord,它总是有一个 Key_ 字段,因为这是我们的数据 model 的要求。
部分数据存储 class:
@Injectable()
export class DataStorage<T extends IDataRecord> {
constructor(private AfDb_:AngularFireDatabase) { }
public Exists(Id:string):Subject<boolean> {
const Status$:Subject<boolean> = new Subject<boolean>();
this.AfDb_.object<T>(`${Id}`).valueChanges()
.subscribe( (OneRecord:T) => {
if (OneRecord !== undefined && OneRecord !== null) {
if (OneRecord.Key_ !== undefined && OneRecord.Key_ !== null && OneRecord.Key_.length > 0) {
Status$.next(true);
} else {
Status$.next(false);
}
} else {
Status$.next(false);
}
})
;
return Status$;
}
以下测试片段适用于真正的 AngularFireDatabase。
describe('DataStorage Service - Using AngularFire', () => {
let ServiceUnderTest:DataStorage<IDataRecord>;
let DependentService:AngularFireDatabase;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AngularFireModule.initializeApp(environment.Firebase)
],
providers: [
AngularFireDatabase,
DataStorage,
]
});
DependentService = TestBed.inject(AngularFireDatabase);
ServiceUnderTest = TestBed.inject(DataStorage);
});
afterEach(() => {
DependentService = null;
ServiceUnderTest = null;
});
it('should be created', () => {
expect(ServiceUnderTest).toBeTruthy('Service was created');
});
it('should confirm a record exists in storage', ( (done) => {
const FileCheck$:Subject<boolean> = ServiceUnderTest.Exists('/Good'); // This exists in Firebase
FileCheck$.subscribe( (Result:boolean) => {
expect(Result).toBeTrue();
done();
});
}));
});
实际测试通过,因为数据存在于 Firebase 中。
我现在正在尝试模拟 AngularFire 部件,这样我就不需要真正的连接来通过测试。 我想更改依赖服务(AngularFire),以便在需要时可以更轻松地将其移动到另一个在线服务。
失败的测试被剪断:
// Create the fake record to be returned - Presence of Key_ with data means the record was found
const GoodDataRecord:ITestInterface = { Key_: 'Fake', Name: 'Fake Record' } ;
const TestData:Observable<ITestInterface> = of<ITestInterface>(GoodDataRecord);
const ValueChangesStub = {
valueChanges: jasmine.createSpy('valueChanges').and.returnValue(TestData)
}
const AfDbObjectStub = {
object: jasmine.createSpy('object').and.returnValue(ValueChangesStub)
}
describe('DataStorage Service - Mocked AngularFire', () => {
let ServiceUnderTest:DataStorage<ITestInterface>;
let DependentService:AngularFireDatabase;
beforeEach( () => {
TestBed.configureTestingModule({
providers: [
DataStorage,
{ provide: AngularFireDatabase, useValue: AfDbObjectStub }
]
});
// Inject both the service-to-test and its (spy) dependency
DependentService = TestBed.inject(AngularFireDatabase);
ServiceUnderTest = TestBed.inject(DataStorage);
});
it('should be created', () => {
expect(ServiceUnderTest).toBeTruthy('Service was created');
});
it ('should return stubbed value from a spy', ( () => {
let Status:boolean;
const FileCheck$:Subject<boolean> = ServiceUnderTest.Exists('UsingStub');
FileCheck$.subscribe( (Result:boolean) => {
Status = Result;
});
expect(Status).toBeTrue();
}));
});
这个测试总是失败。 Expected undefined to be true.
在 FileCheck$ subscribe 块中添加 console.log() 不会写出任何内容。 这没有被执行。 但是,如果我在 DataStorage class 中添加一个 console.log,我确实会看到返回的假数据。
this.AfDb_.object<T>(`${BasePath}/${Id}`).valueChanges()
.subscribe( (OneRecord:T) => {
console.log(OneRecord.Key_);
这将显示真实测试的“好”,以及失败测试的“假”。
根据@Alif50:
it ('should return stubbed value from a spy', ( done => {
const FileCheck$:Subject<boolean> = ServiceUnderTest.Exists('Fake');
FileCheck$.subscribe( (Result:boolean) => {
expect(Result).toBeTrue();
done();
});
}));
这现在引入了一个不同的错误: Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
尝试将第二个测试更改为:
it ('should return stubbed value from a spy', done => {
let Status:boolean;
const FileCheck$:Subject<boolean> = ServiceUnderTest.Exists('UsingStub');
FileCheck$.subscribe( (Result:boolean) => {
Status = Result;
expect(Status).toBeTrue();
done(); // call done to let the test know you are done
});
});
按照您呈现的方式,断言( expect(Status).toBeTrue()
)发生在subscribe
块运行之前,因为.subscribe
是异步的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.