【问题标题】:Creating a Jest Unit Test for Express Middleware function为 Express 中间件函数创建 Jest 单元测试
【发布时间】:2021-08-17 20:43:40
【问题描述】:

我正在尝试通过检查 NextFunction 是否已被调用来为 Express 中间件函数创建单元测试。

SecurityWrapper.test.ts

let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
const nextFunction: NextFunction = jest.fn();

test("validates ownership correctly", () => {
  const security = new SecurityWrapper("config.json");
  mockRequest = {
    accessToken: new AccessToken("token"),
    headers: {Authorization: "Bearer token"},
    params: {id: "xxx-yyy"}
  };

  const uri = "https://myresource.uri";

  mocked(Utils).getClientServiceAccountToken.mockResolvedValueOnce("token");

  mock.onGet(uri).reply(200, { owner: { id: "Mr. Bean"}});

  AccessToken.prototype.decode = jest.fn().mockReturnValueOnce({sub: "Mr. Bean"});

  const owner = security.validateOwnership();
  owner(mockRequest as Request, mockResponse as Response, nextFunction);

  expect(nextFunction).toHaveBeenCalled();
});

SecurityWrapper.ts

import validateOwnership from "./middleware/validateOwnership";
// ...
validateOwnership (resId?: string) {
  return validateOwnership(this.config, resId);
}
// ...

validateOwnership.ts

export default function validateOwnership (config: Config, resId?: string) {
  return function owner (req: Request, res: Response, next: NextFunction):
    void {
    const id = resId ? resId : req.params.id;

    if (id === undefined) {
      res.sendStatus(400);
      return;
    }
    const clientBasicAuth = config.clientCredentials;

    if (clientBasicAuth === undefined || clientBasicAuth.length === 0) {
      res.sendStatus(400);
      return;
    }

    fetchResourceOwner(config, id, `${clientBasicAuth}`)
      .then((owner) => {
        const own = req.accessToken.decode().sub;
        if (owner === own) {
          // This function does get called by the tests, but test always fails regardless
          next();
          return;
        } else {
          res.sendStatus(403);
          return;
        }
      })
      .catch(() => {
        res.sendStatus(401);
      });
  };
}

nextFunction mock 确实被调用(通过 mockImplementation 检查并记录到控制台),但测试总是失败。我在这里做错了什么?

【问题讨论】:

  • 执行此操作时收到的失败评论是什么?
  • @Shrirang 失败注释为:expect(jest.fn()).toHaveBeenCalled() 预期通话次数:>=1 接听通话次数:0

标签: typescript unit-testing jestjs


【解决方案1】:

validateOwnership 异步调用next 函数,因此expect 检查发生在next 被调用之前。通常你想通过使用异步测试来解决这个问题。 在这种情况下,它可能如下所示:

test("validates ownership correctly", async () => {
  // setup code

  // we convert callback to promise
  await new Promise(resolve => {
    owner(mockRequest as Request, mockResponse as Response, () => {
      resolve();
      nextFunction();
    });
  });

  expect(/* ... */);
});

如果您只检查 next 是否已被调用,您甚至可能不需要模拟 nextFunction,因为如果未解决承诺,测试将失败并出现超时错误:

await new Promise(resolve => owner(mockRequest as Request, mockResponse as Response, resolve));

【讨论】:

  • 这确实可以让测试通过,谢谢!
猜你喜欢
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
  • 2019-05-16
  • 2020-07-31
  • 2019-10-02
相关资源
最近更新 更多