繁体   English   中英

当测试的 function 没有使用 async/await 时,我可以在 Jest 中使用 async/await 吗?

[英]Can I use async/await in Jest, when the tested function is not using async/await?

我有一个简单的 controller 用于添加新用户。 解析成功后(用户添加),controller发送202响应。 如您所见,function 使用的是 then/catch,而不是使用 async/await。

const addUserController = function (req, res, next) {
    Users.addOne(req.userid, req.body.email)
    .then(() => {
      res.status(202).send();
    })
    .catch((err) => {
      console.log(err);
      res.status(500).json({ message: "Internal server error." });
    });
};

当我在 Jest 中测试这个 function 时,function 立即执行,而不转到 then() 部分,导致错误的 200 代码,而不是 202,因此以下测试失败:

it("Should add a user", () => {
    let req, res, next, pool;
    pool = new Pool();
    req = httpsMocks.createRequest();
    res = httpsMocks.createResponse();
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    apiController.addUserController(req, res, next);
    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

但是,当我这样做时:

it("Should add a user", async () => {
    let req, res, next, pool;
    pool = new Pool();
    req = httpsMocks.createRequest();
    res = httpsMocks.createResponse();
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    await apiController.addUserController(req, res, next);
    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

那就是我添加了异步/等待,它工作正常 - 响应状态代码是 202,这意味着等待 function 并且测试通过。 但为什么? 当我 hover 超过新添加的 'await' VS 代码提示

'await' 对这个表达式的类型没有影响。

嗯,这是有道理的 - 它应该没有效果,因为经过测试的 function 不是异步的,所以它不应该工作,但是它可以工作 - 只有当我将 async/await 添加到 Jest function 时它才能正常工作。

有人可以向我解释一下吗?

我添加了 async/await,它工作正常 - 响应状态代码为 202,这意味着等待 function 并且测试通过。 但为什么?

不,正如您从缺少的返回值中得出的结论,不等待 function。 您的代码相当于

apiController.addUserController(req, res, next);
await undefined;

现在,为什么它仍然有所作为? 因为使用await ,测试在运行expect()调用之前会等待一小段时间,而这一小段位足以让您的模拟池返回一个值并执行第一个.then()处理程序。

但是,您现在基本上引入了竞争条件。 在 addUserController 中有更长的addUserController链会使测试失败。 甚至对.then().catch()中创建的 500 状态的测试可能已经无法正常工作。

这很脆弱,不要写这样的测试。 一种解决方案是简单地从addUserController return promise 链并await它 - 只要没有其他调用者对此感到困惑,这是简单的修复。 另一种解决方案是实际等待模拟响应实际发送。 如果我正确阅读了node-mocks-http的文档,这样的东西应该可以工作:

it("Should add a user", async () => {
    const { once, EventEmitter } = require('events');
    const pool = new Pool();
    const req = httpsMocks.createRequest();
    const res = httpsMocks.createResponse({ eventEmitter: EventEmitter });
    res.next = null;
    req.userid = 1;
    req.body = {
      id: 2
    }
    pool.query.mockResolvedValue({rows:[], rowCount: 1});
    const responseEndPromise = once(res, 'end');
    
    apiController.addUserController(req, res, next);
    await responseEndPromise;

    expect(res.statusCode).toBe(202);
    expect(pool.query).toBeCalledTimes(1);
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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