如何断言在 Jest 测试中使用 `async` 调用了依赖项?

How to assert that a dependency was called using `async` in a Jest test?

我有一个服务可以用配置切换的替代行为来装饰异步函数:

// decorator.js
const config = require('./config');
const logger = require('./logger');

function addAlternateBehavior(originalAsyncFunction, alternateAsyncFunction) {
    return async () => {
        if (config.useAlternateBehavior) {
            await alternateAsyncFunction();
        } else {
            await originalAsyncFunction();
        }
        logger.info('Behavior finished executing');
    };
}

exports.addAlternateBehavior = addAlternateBehavior;

我有一个 Jest 单元测试,用于验证在相应配置时是否调用了替代行为:

// decorator.test.js
const decorator = require('./decorator');
const config = require('./config');

it('returned function should use alternate behavior when configured to do so', async () => {
    // Arrange
    const originalAsyncFunction = jest.fn();
    const alternateAsyncFunction = jest.fn();
    config.useAlternateBehavior = true;

    // Act
    const decoratedFunction = decorator
        .addAlternateBehavior(originalAsyncFunction, alternateAsyncFunction);
    await decoratedFunction();

    // Assert
    expect(originalAsyncFunction.mock.calls.length).toBe(0);
    expect(alternateAsyncFunction.mock.calls.length).toBe(1);
});

我想断言,当您使用 await 调用装饰函数时,它也会等待预期的行为。但是,在装饰器中,如果我将 await alternateAsyncFunction(); 更改为 alternateAsyncFunction(),我的单元测试仍然会通过。

如何在单元测试中断言由 addAlternateBehavior() 修饰的函数等待 alternateAsyncFunctionoriginalAsyncFunction

为您的 async 函数提供一个在调用内部 mock 之前至少等待两个事件循环周期的实现。然后测试内部 mock 是否被调用:

const decorator = require('./decorator');
const config = require('./config');

it('returned function should use alternate behavior when configured to do so', async () => {
    // Arrange
    const originalInner = jest.fn();
    const originalAsyncFunction = jest.fn(async () => {
      await Promise.resolve();
      await Promise.resolve();
      originalInner();
    });
    const alternateInner = jest.fn();
    const alternateAsyncFunction = jest.fn(async () => {
      await Promise.resolve();
      await Promise.resolve();
      alternateInner();
    });
    config.useAlternateBehavior = true;

    // Act
    const decoratedFunction = decorator
        .addAlternateBehavior(originalAsyncFunction, alternateAsyncFunction);
    await decoratedFunction();

    // Assert
    expect(originalAsyncFunction.mock.calls.length).toBe(0);
    expect(originalInner.mock.calls.length).toBe(0);
    expect(alternateAsyncFunction.mock.calls.length).toBe(1);
    expect(alternateInner.mock.calls.length).toBe(1);
});

如果 addAlternateBehavior() 创建的函数没有 await 则内部 mock 不会被调用。

请注意,需要两个 await Promise.resolve(); 语句,因为第一个语句在 await decoratedFunction();

期间运行的事件循环周期中解析