我正在尝试测试我的数据服务,我可以使用真实的服务(AngularFireDatabase)来做,但我无法让模拟的版本进行测试。
我的DataStorage类用于结合本地存储、远程存储和其他功能。这使得我们的应用程序可以轻松地改变我们集成到的服务。
因此,我们对一些基本结构进行了扩展,比如IDataRecord,它将始终有一个Key_字段,因为这是我们数据模型的要求。
DataStorage类的一部分。
@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$订阅块中添加一个控制台.log(),并没有写出任何东西。 这是不被执行的。 然而,如果我在DataStorage类中添加一个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)
试着把第2个测试改成这样。
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
是异步的。