【发布时间】:2019-03-14 14:20:30
【问题描述】:
我知道关于 SO 有很多类似的问题,但我相信我的问题是不同的,目前的任何答案都没有回答。
我正在 Express.JS 中测试一个 REST API。下面是一个最小的工作示例和几个不同编号的测试用例。
const express = require("express");
let request = require("supertest");
const { promisify } = require("util");
const app = express();
request = request(app);
const timeOut = promisify(setTimeout);
const timeOut2 = time =>
new Promise(resolve => {
setTimeout(resolve, time);
});
app.locals.message = "Original string";
app.get("/one", async (req, res) => {
await timeOut(1000);
res.send(app.locals.message);
});
app.get("/two", (req, res) => {
res.send(app.locals.message);
});
app.get("/three", async (req, res) => {
await timeOut2(1000);
res.send(app.locals.message);
});
test("1. test promisify", async () => {
expect.assertions(1);
const response = await request.get("/one");
expect(response.text).toEqual("Original string");
});
test("2. test promisify with fake timers", () => {
expect.assertions(1);
jest.useFakeTimers();
request.get("/one").then(res => {
expect(res.text).toEqual("Original string");
});
jest.runAllTimers();
});
test("3. test promisify with fake timers and returning pending promise", () => {
expect.assertions(1);
jest.useFakeTimers();
const response = request.get("/one").then(res => {
expect(res.text).toEqual("Original string");
});
jest.runAllTimers();
return response;
});
test("4. test no timeout", async () => {
expect.assertions(1);
const response = await request.get("/two");
expect(response.text).toEqual("Original string");
});
test("5. test custom timeout", async () => {
expect.assertions(1);
const response = await request.get("/three");
expect(response.text).toEqual("Original string");
});
test("6. test custom timeout with fake timers", () => {
expect.assertions(1);
jest.useFakeTimers();
const response = request.get("/three").then(res => {
expect(res.text).toEqual("Original string");
});
jest.runAllTimers();
return response;
});
单独运行测试表明只有测试 5 通过。 那么我的第一个问题是为什么测试 5 通过而不是测试 1,考虑到它们是完全相同的测试,除了基于承诺的延迟的不同实现。 两种实现都可以在 Jest 测试之外完美运行(使用 Supertest 没有 Jest 进行测试)。
虽然测试 5 确实通过了,但它使用的是实时计时器,因此并不理想。就我所见,测试 6 应该是等效的假计时器(我还尝试了在 then 正文中调用 done() 的版本),但这也失败了。
我的 web 应用程序有一个带有使用 util.promisify(setTimeout) 的处理程序的路由,因此 Jest 试图测试它的事实,即使使用真正的计时器,也使得该框架对我的用处大大降低。考虑到自定义实现(测试 5)确实有效,这似乎是一个错误。
尽管如此,Jest 仍然无法使用模拟计时器进行测试 6,因此即使我在我的应用程序中重新实现延迟(我不想这样做),我仍然不得不忍受无法进行的缓慢测试加快速度。
这些问题中的任何一个都是预期的行为吗?如果不是我做错了什么?
【问题讨论】:
-
"为什么测试 5 通过而不是测试 1,因为它们是完全相同的测试" - 测试 5 使用
async函数并且确实返回了一个对开玩笑的承诺,与测试 3 相比,与测试 1 更相似。 -
是的,Jest 不能模拟一个承诺的
setTimeout听起来像是一个错误。还是我们应该称其为promisify的一个功能? -
@skyboyer 你确定吗?异步函数返回没有返回关键字的承诺,不是吗?请注意,当 Jest 文档中的示例具有异步功能时,它们都没有使用
return。 -
@Bergi 那是我的错误。我在我的编辑器中更新了它,但没有将更改复制到这里。 1 和 5 现在完全等价了
-
@skyboyer 实际上,如果您查看 docs 的 setTimeout,您会看到直接引用了 promisified 版本并给出了示例。
标签: javascript node.js jestjs es6-promise