代码之家  ›  专栏  ›  技术社区  ›  snak

如何使用should断言函数已“等待”异步函数。js

  •  2
  • snak  · 技术社区  · 7 年前

    我有一个异步函数 f 调用另一个异步函数 g .测试是否 F 电话 G ,我在存根 G 使用sinon并断言它被称为使用should。js。

    'use strict';
    
    require('should-sinon');
    const sinon = require('sinon');
    
    class X {
        async f(n) {
            await this.g(n);
            // this.g(n); // I forget to insert `await`!
        }
        async g(n) {
            // Do something asynchronously
        }
    }
    
    describe('f', () => {
        it('should call g', async () => {
            const x = new X();
            sinon.stub(x, 'g').resolves();
            await x.f(10);
            x.g.should.be.calledWith(10);
        });
    });
    

    但即使我忘记使用,这个测试还是通过了 await 打电话的时候 G 在里面 F .

    捕获此错误的方法之一是使存根返回一个虚拟承诺,并检查其 then 被称为。

    it('should call g', async () => {
        const x = new X();
        const dummyPromise = {
            then: sinon.stub().yields()
        };
        sinon.stub(x, 'g').returns(dummyPromise);
        await x.f(10);
        x.g.should.be.calledWith(10);
        dummyPromise.then.should.be.called();
    });
    

    但这有点麻烦。有什么方便的方法吗?

    2 回复  |  直到 7 年前
        1
  •  0
  •   B M    7 年前

    你的榜样 f 显示了有缺陷的代码设计,如果编写相同的函数时没有 async/await 语法:

    f(n) { return g(n).then(()=>{}); }

    这实现了同样的行为——无论 g 决心变得很难说(假设你不知道 F 返回 G 的承诺,这与不知道 F 等待 G ).如果 F 对结果不感兴趣 G 它应该只是简单地归还它,而不是隐藏它。然后你可以简单地测试结果。

    如果你的意思是 F 可能要触发几个 async 按顺序呼叫 await 好几个 g_1 , g_2 ,... 为了解决这个问题,您可以通过在 g_n+1 那是虚假的承诺 g_n 已经解决了。一般来说,您测试虚拟承诺状态的方法是好的。

        2
  •  0
  •   sripberger    7 年前

    而不是打短棍 then ,你最好别插嘴 g 在下一个事件循环迭代中设置一些布尔值。然后,您可以在调用后检查此布尔值 f 确保 F 等待它:

    it('should call g', async () => {
        const x = new X();
        let gFinished = false;
        sinon.stub(x, 'g').callsFake(() => {
            return new Promise((resolve) => {
                setImmediate(() => {
                    gFinished = true;
                    resolve();
                });
            });
        });
        await x.f(10);
        x.g.should.be.calledWith(10);
        gFinished.should.be.true();
    });
    

    编辑:当然,这不是 完美的 保证因为你可以 F 等待任何承诺,至少等待它所需要的时间 G 解决问题。就像这样:

    async f(n) {
        this.g(n);
        await new Promise((resolve) => {
            setImmediate(() => {
                resolve();
            });
        });
    }
    

    这将导致我编写的测试通过,尽管它仍然不正确。所以实际上,这取决于你对考试的要求有多严格。你想这样吗 简直不可能 假阳性?或者,如果一些明显的诡计可能会把它扔掉,这还可以吗?

    在大多数情况下,我发现后者是可以的,但实际上这取决于你和/或你的团队。