简体   繁体   English

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

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

I have a simple controller for adding new users.我有一个简单的 controller 用于添加新用户。 After the successful resolution (user added), the controller sends a 202 response.解析成功后(用户添加),controller发送202响应。 As you can see, the function is using then/catch and is not using async/await.如您所见,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." });
    });
};

When I am testing this function in Jest with the, the function executes immediately, without going to the then() part, resulting in a mistaken 200 code, instead of 202, so the following test fails:当我在 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);
});

However, when I make it like that:但是,当我这样做时:

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);
});

that is I add async/await, it works alright - the response status code is 202, meaning the function was awaited and the test passes.那就是我添加了异步/等待,它工作正常 - 响应状态代码是 202,这意味着等待 function 并且测试通过。 But why?但为什么? When I hover over the newly added 'await' VS code is suggesting that当我 hover 超过新添加的 'await' VS 代码提示

'await' has no effect on the type of this expression. 'await' 对这个表达式的类型没有影响。

Well it makes sense - it should have no effect, as the tested function is not async, so it shouldn't work, but well, it works - only when I add the async/await to the Jest function it works fine.嗯,这是有道理的 - 它应该没有效果,因为经过测试的 function 不是异步的,所以它不应该工作,但是它可以工作 - 只有当我将 async/await 添加到 Jest function 时它才能正常工作。

Could someone explain this to me?有人可以向我解释一下吗?

I add async/await, it works alright - the response status code is 202, meaning the function was awaited and the test passes.我添加了 async/await,它工作正常 - 响应状态代码为 202,这意味着等待 function 并且测试通过。 But why?但为什么?

No, as you concluded from the missing return value, the function is not awaited.不,正如您从缺少的返回值中得出的结论,不等待 function。 Your code is equivalent to您的代码相当于

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

Now, why does it still make a difference?现在,为什么它仍然有所作为? Because with the await , the test is waiting a tiny bit before running the expect() calls, and that tiny bit is enough for your mocked pool to return a value and have the first .then() handler be executed.因为使用await ,测试在运行expect()调用之前会等待一小段时间,而这一小段位足以让您的模拟池返回一个值并执行第一个.then()处理程序。

However, you now basically introduced a race condition.但是,您现在基本上引入了竞争条件。 Having a longer promise chain in the addUserController would make the test fail.在 addUserController 中有更长的addUserController链会使测试失败。 Maybe even a test for the 500 status being created in .then().catch() might already not work.甚至对.then().catch()中创建的 500 状态的测试可能已经无法正常工作。

This is very fragile, don't write a test like that.这很脆弱,不要写这样的测试。 One solution would be to simply return the promise chain from addUserController and await it - as long as no other callers will be confused by that, it's the simple fix.一种解决方案是简单地从addUserController return promise 链并await它 - 只要没有其他调用者对此感到困惑,这是简单的修复。 Another solution is to actually wait for the mock response to be actually sent.另一种解决方案是实际等待模拟响应实际发送。 If I read the docs of node-mocks-http right, something like this should work:如果我正确阅读了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