为什么其中一项完成/等待测试有效而另一项无效?

时间:2018-10-09 06:36:53

标签: angular unit-testing jasmine karma-jasmine

我有一个要测试的异步方法:

async getGeneralStats(): Promise<GeneralStats> {
    console.log("getGeneralStats()");

    let recoveredGeneralStats = await this.storage.get(StorageKeyItems.GeneralStats);
    console.log("recoveredGeneralStats", recoveredGeneralStats);

    if (!recoveredGeneralStats) {
        console.warn("There were no general stats, creating new one")
        this.generalStats = new GeneralStats();
        await this.storage.set(StorageKeyItems.GeneralStats, this.generalStats);
    } else {
        this.generalStats = recoveredGeneralStats;
        console.log("Recovered GeneralStats : ");
        console.dir(this.generalStats)
    }

    console.log("Returning from getGeneralStats")
    return this.generalStats;
}

我想测试一下(要开始):1.如果storage.get返回null时,调用了storage.set,并且调用了storage.get

第一个测试成功了,就是这样的:

    it("should GET the GeneralStats from Storage Service ", ((done) => {
        // Arrange
        let spy = spyOn(storage, 'get').and.callFake((storageKey) => {
            done();
            return Promise.resolve(null);
        })

        // Act
        statisticsProvider.getGeneralStats();

        // Assert
        expect(spy).toHaveBeenCalledWith(StorageKeyItems.GeneralStats);
    }));

但是当我尝试以相同的方式运行第二个测试时,它失败了:

    it("should SET GeneralStats in Storage if not General Stats were retrieved ", ((done) => {
        // Arrange
        spyOn(storage, 'get').and.callFake((storageKey) => {
            console.log("spyGet was called");
            return Promise.resolve(null);
        })

        let spySet = spyOn(storage, 'set').and.callFake((storageKey, value) => {
            console.log("spySet was called");
                          done();
            return Promise.resolve(null);
        })

        // Act
        statisticsProvider.getGeneralStats();

        // Assert
            expect(spySet).toHaveBeenCalledWith(StorageKeyItems.GeneralStats,statisticsProvider.generalStats);

    }));

失败错误显示:"Expected spy set to have been called with [ 'GeneralStats', undefined ] but it was never called.",但控制台日志显示其他内容:

getGeneralStats()
spyGet was called
recoveredGeneralStats null
There were no general stats, creating new one
spySet was called
FAILED StatisticsProvider #getGeneralStats should SET GeneralStats in Storage if not General Stats were retrieved 
Returning from getGeneralStats
ERROR Expected spy set to have been called with [ 'GeneralStats', undefined ] but it was never called. 

我不知道为什么它说什么时候没有被调用。我什至试图“欺骗”并创建一个变量,该变量在调用spySet时变为true,但仍然无法正常工作。

    it("should SET GeneralStats in Storage if not General Stats were retrieved ", ((done) => {
        let spyWasCalled = false;
        // Arrange
        spyOn(storage, 'get').and.callFake((storageKey) => {
            console.log("spyGet was called");
            return Promise.resolve(null);
        })


        let spySet = spyOn(storage, 'set').and.callFake((storageKey, value) => {
            console.log("spySet was called");
            spyWasCalled = true;
            return Promise.resolve(null);
        })

        // Act
        statisticsProvider.getGeneralStats().then(() => {
            done();

        });

        // Assert
        expect(spyWasCalled).toBeTruthy();
    }));

如果我将方法调用过去的测试后将expect()放在.then中,但是为什么以前不需要它呢?

    it("should SET GeneralStats in Storage if not General Stats were retrieved ", ((done) => {
        // Arrange
        spyOn(storage, 'get').and.callFake((storageKey) => {
            console.log("spyGet was called");
            return Promise.resolve(null);
        })

        let spySet = spyOn(storage, 'set').and.callFake((storageKey, value) => {
            console.log("spySet was called");

            return Promise.resolve(null);
        })

        // Act
        statisticsProvider.getGeneralStats().then(() => {

            // Assert
            expect(spySet).toHaveBeenCalledWith(StorageKeyItems.GeneralStats, statisticsProvider.generalStats);
            done();
        });

    }));

1 个答案:

答案 0 :(得分:1)

两个测试用例均给出不一致的测试结果。因为:

  1. expect()可能由于其异步工作而在目标函数完成其命令之前执行。 -测试用例运行时,getGeneralStats()给出了Promise,并且可能会或可能不会继续运行expect(),这可能会导致失败。

  2. done()在错误的位置。异步测试用例完成后,将调用done()的目的。因此,当您确定所有异步执行均已完成时,应在expect() 之后调用它。 -在第一个(和第二个)测试用例中,它可能根本不运行expect()!因为done()可能在那些callFakes中的expect()之前被调用。

要进行验证,请在console.log()之前(或之后)添加更多expect()。因此,您可以查看callFake闭包是否在期望值之前或之后运行。

我的建议

由于被测函数具有异步工作原理,因此您也必须以异步方式预期结果。

茉莉花记录了here

您可以使用async/awaitPromisedone()。这是使用async/await的示例:

it("should SET GeneralStats in Storage if not General Stats were retrieved ", (async () => {
    // Arrange
    spyOn(storage, 'get').and.callFake((storageKey) => {
        console.log("spyGet was called");
        return Promise.resolve(null);
    })

    let spySet = spyOn(storage, 'set').and.callFake((storageKey, value) => {
        console.log("spySet was called");
        return Promise.resolve(null);
    })

    // Act
    await statisticsProvider.getGeneralStats();

    // Assert
    expect(spySet).toHaveBeenCalledWith(StorageKeyItems.GeneralStats, statisticsProvider.generalStats);

}));