【问题标题】:How to mock mongodb client when testing Nexts page api with jest?用 jest 测试 Nexts 页面 api 时如何模拟 mongodb 客户端?
【发布时间】:2022-01-29 23:47:17
【问题描述】:

我想用 jest 测试一个页面下一页 api 文件,虽然目前测试运行良好,但我遇到了一些问题

  1. 每个页面 API POST 请求实际上都是在向 mongo 数据库发送数据,即使我正在运行测试;这是不可取的,因为我不希望在测试此类 POST 请求时将测试数据放在数据库中
  2. 在某些情况下,我想模拟 mongo 连接失败,以测试 500 状态错误响应,但我不确定如何执行此操作

我如何模拟 mongoclient 连接,以便在连接成功后测试将项目插入数据库,或故意导致 mongo 客户端连接错误?

    newsletter.ts (PAGE API FILE)
    import type { NextApiRequest, NextApiResponse } from 'next'
import { MongoClient } from 'mongodb'

async function connectDatabase() {
  const client = await MongoClient.connect(<url>)
  return client
}

async function insertDocument(client: MongoClient, document: { email: string }) {
  const db = client.db()
  await db.collection('newsletter').insertOne(document)
}

async function handler(req: NextApiRequest, res: NextApiResponse) {
  const userEmail = JSON.parse(req.body).email
  if (!userEmail || !userEmail.includes('@')) {
    res.status(422).json({ message: 'Invalid email address' })
    return
  }

  let client
  try {
    client = await connectDatabase()

  } catch (error) {
    res.status(500).json({ message: 'Connecting to the database failed!' })
    return
  }

  try {
    await insertDocument(client, { email: userEmail })

  } catch(error) {
    res.status(500).json({ message: 'Inserting data failed!' })
    return
  }

  client.close()

  res.status(201).json({ message: 'Signed up!' })

}

export default handler

这是测试代码

newsletter.test.tsx (PAGE API TEST FILE)

import type { NextApiRequest, NextApiResponse } from 'next'
import {
  createMocks as _createMocks,
  Mocks,
  RequestOptions,
  ResponseOptions,
} from 'node-mocks-http'

import newsletter from '../../pages/api/newsletter'



const createMocks = _createMocks as (
  reqOptions?: RequestOptions,
  resOptions?: ResponseOptions

) => Mocks<NextApiRequest, NextApiResponse>

describe('Test responses for newsletter api', () => {
  it('Should return status 201 with valid request body', async () => {
    const { req, res } = createMocks({
      method: 'POST',
      body: JSON.stringify({
        email: 'abc@email.com',
      }),
    })
    await newsletter(req, res)
    expect(res._getStatusCode()).toBe(201)
    expect(JSON.parse(res._getData())) .toEqual(
      expect.objectContaining({
        message: 'Signed up!',
      })
    )
  })

  it('Should return status 422 with invalid req body', async () => {
    const { req, res } = createMocks({
      method: 'POST',
      body: JSON.stringify({
        email: 'abcemail.com',
      }),
    })
    await newsletter(req, res)
    expect(res._getStatusCode()).toBe(422)
    expect(JSON.parse(res._getData())).toEqual(
      expect.objectContaining({
        message: 'Invalid email address',
      })
    )
  })
})

【问题讨论】:

    标签: mongodb unit-testing jestjs next.js


    【解决方案1】:

    发现这个answer 帮助我解决了问题

    为了模拟 mongoclient,我只需要使用 jest.spyOn,并将用户的所有其他函数链接到数据库中。这也阻止了对服务器的真正调用,并且不再发送测试数据。为了模拟状态 500 错误,我只是模拟了一个被拒绝的承诺。

    代码最终变成了这样:

    import type { NextApiRequest, NextApiResponse } from 'next'
    import {
      createMocks as _createMocks,
      Mocks,
      RequestOptions,
      ResponseOptions,
    } from 'node-mocks-http'
    import { MongoClient } from 'mongodb'
    
    import newsletter from '../../pages/api/newsletter'
    
    
    
    const createMocks = _createMocks as (
      reqOptions?: RequestOptions,
      resOptions?: ResponseOptions
    ) => Mocks<NextApiRequest, NextApiResponse>
    describe('Test responses for newsletter api', () => {
    
      afterEach(() => {
        jest.resetAllMocks()
      })
    
      it('Should return status 500 on failure to connect to database', async () => {
        const { req, res } = createMocks({
          method: 'POST',
          //@ts-ignore
          body: JSON.stringify({
            email: 'abc@email.com',
          }),
        })
        const connectSpy = jest.spyOn(MongoClient, 'connect').mockRejectedValueOnce(new Error)
        await newsletter(req, res)
        expect(connectSpy).toHaveBeenCalled()
        expect(res._getStatusCode()).toBe(500)
      })
    
    
      it('Should return status 201 with valid request body', async () => {
        const { req, res } = createMocks({
          method: 'POST',
          //@ts-ignore
          body: JSON.stringify({
            email: 'abc@email.com',
          }),
        })
        const insertOne = jest.fn().mockResolvedValueOnce({ acknowleged: true })
        const collection = jest.fn().mockReturnValueOnce({ insertOne })
        const connectSpy = jest.spyOn(MongoClient, 'connect').mockResolvedValueOnce({ db: jest.fn().mockReturnValueOnce({ collection }), close: jest.fn() })
        await newsletter(req, res)
        expect(connectSpy).toHaveBeenCalled()
        expect(res._getStatusCode()).toBe(201)
        expect(JSON.parse(res._getData())) .toEqual(
          expect.objectContaining({
            message: 'Signed up!',
          })
        )
      })
    
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-06
      • 1970-01-01
      • 2019-05-23
      • 1970-01-01
      相关资源
      最近更新 更多