【问题标题】:How to mock a method inside Express router Jest test?如何在 Express 路由器 Jest 测试中模拟方法?
【发布时间】:2020-07-14 14:03:19
【问题描述】:

我正在尝试使用 Jest + Supertest 在 Node.js 应用程序中测试路由器,但我的路由器正在调用服务,该服务正在调用端点:

router.post('/login', async (req, res, next) => {
  try {
    const { username, password } = req.body;

    // I WANT TO MOCK userService.getUserInfo FUNCTION, BECAUSE IT IS MAKING A POST CALL
    const identity = await userService.getUserInfo(username, password);

    if (!identity.authenticated) {
      return res.json({});
    }

    const requiredTenantId = process.env.TENANT_ID;
    const tenant = identity.tenants.find(it => it.id === requiredTenantId);

    if (requiredTenantId && !tenant) {
      return res.json({});
    }

    const userResponse = {
      ...identity,
      token: jwt.sign(identity, envVars.getVar(envVars.variables.AUTH_TOKEN_SECRET), {
        expiresIn: '2h',
      }),
    };

    return res.json(userResponse);
  } catch (err) {
    return next(err);
  }
});

这是我的测试,效果很好:

test('Authorized - respond with user object', async () => {
  const response = await request(app)
    .post('/api/user/login')
    .send(users.authorized);
  expect(response.body).toHaveProperty('authenticated', true);
});

getUserInfo 函数如下所示:

const getUserInfo = async (username, password) => {
  const identity = await axios.post('/user', {username, password});

  return identity;
}

但它在路由器内执行getUserInfo 方法,并且此方法正在进行 REST 调用 - 我想模拟此方法以避免 REST 调用其他服务。 怎么可能做到?

我在 Jest 文档 https://jestjs.io/docs/en/mock-function-api.html#mockfnmockimplementationfn

中发现了一个 mockImplementation 函数

但是我如何在超测测试中模拟 func 呢?

【问题讨论】:

  • 我猜你在这些测试之前启动了一个“真正的”api服务器,这意味着你的测试在不同的节点上下文(单独的进程)中运行,因此没有为什么测试可以模拟某些东西在里面。我说的对吗?
  • 我在描述中添加了getUserInfo
  • 我想模拟这个函数,以免调用外部 API
  • 我的假设是否正确?你启动一个 API 服务器并运行测试?
  • 不,'API server' 是外部服务

标签: javascript node.js unit-testing express jestjs


【解决方案1】:

您可以在测试顶部使用 jest 的自动模拟

像这样:

jest.mock('./path/to/userService');

// and include it as well in your test
const userService = require('./path/to/userService');

它将生成整个模块的模拟,每个函数都将替换为 jest.fn() 而没有实现

然后取决于 userService 如果它只是一个对象,它的 getUserInfo 方法将是一个 jest.fn() ,你可以像这样设置它的返回值:

// resolved value as it should return a promise
userService.getUserInfo.mockResolvedValue(mockIdentity);

并且 mockIdentity 必须看起来像这样:

const mockIdentity = {
      authenticated: true,
      tenants: [
        {
          id: "x12",
          mockInfo: "mock-info-value"
        }
      ],
      mother: "Superwoman",
      father: "Superman"
    })
  }

【讨论】:

  • 非常感谢!但是我应该把userService.getUserInfo.mockResolvedValue(mockIdentity);放在哪里?我正在使用 supertest 请求及其语法:(request(...).post(...).send(...))
  • @Karen 在发起请求之前request(...).post(...).send(...)
  • 我收到一个错误:expect(received).toHaveProperty(path, value) Expected path: "authenticated" Received path: [] Expected value: true Received value: {"error": "Cannot read property 'find' of undefined"} 将尝试修复它并让您知道结果
  • 它响应的是空对象,而不是mockidentityobj
  • 我有一个类似的场景,除了我的fetch 调用位于最终根据响应填充请求对象的中间件中。这对你有用吗@Karen
猜你喜欢
  • 2019-06-18
  • 2020-03-19
  • 1970-01-01
  • 2020-01-05
  • 1970-01-01
  • 2021-01-11
  • 2017-08-17
  • 2021-11-06
  • 1970-01-01
相关资源
最近更新 更多