繁体   English   中英

如何使用 AngularFireDatabase 和 Jasmine Spy/Mock 测试 Angular 服务

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM