如何使用AngularFireDatabase与Jasmine SpyMock测试Angular服务?

问题描述 投票:0回答:1

我正在尝试测试我的数据服务,我可以使用真实的服务(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)

angular testing jasmine angularfire
1个回答
0
投票

试着把第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 是异步的。

© www.soinside.com 2019 - 2024. All rights reserved.