javascript - 开 Jest : How to properly test a Javascript service using MongoDB

标签 javascript mongodb testing jestjs

我是 Jest 的初学者。

我有一个使用依赖注入(inject)的UserService

public async getAll() {
  const userRecords = await this.userModel.find().select('name').catch((e) => {
    throw new HttpException(500, 'Error while fetching users.', e)
  });
  return <[IUser]>userRecords;
}

我想测试一下这个功能。以下是我可以运行的测试:

  1. 调用路由,并检查生成的 JSON 是否正确
  2. 获取数据库内容,并检查其是否符合预期
  3. 只需测试 getAll 函数

我认为 1 和 2 是显而易见的,并且涵盖了不同类型的事物。 1 涵盖请求部分,2 涵盖数据库部分。但是3号呢?如何“仅测试”getAll 函数?

我已经尝试过这个:

const userModel = {
  find: (user) => {
    return [
      { id: 'user1' },
      { id: 'user2' }
    ]
  },
};
const userService = new UserService(userModel);
const userRecords = await userService.getAll();

expect(argumentRecord).toBeDefined();

但显然它失败了,因为 select 未定义

我还应该模拟select()吗?我应该以不同的方式组织我的代码吗?

最佳答案

如果要编写此测试,我将使用 jest.fn(implementation) 模拟函数以便可以对函数调用强制执行期望。

const userQuery = {
    select: jest.fn(() => Promise.resolve([]))
};

const userModel = {
    find: jest.fn(() => userQuery)
};

const userService = new UserService(userModel);
const userRecords = await userService.getAll();

expect(userRecords).toEqual([]);
expect(userModel.find).toHaveBeenCalled();
expect(userQuery.select).toHaveBeenCalledWith('name');

对函数调用执行预期可能听起来有点矫枉过正,但它显式验证了 getAll 实际上正在使用该模拟。

我还会以这样的方式构建测试,这样我就可以测试各种代码路径,而无需重新实现整个模拟。

describe('getAll()', () => {

    let userQuery, userModel, userService;
    beforeEach(() => {
        userQuery = {
            select: jest.fn(() => Promise.resolve([]))
        };

        userModel = {
            find: jest.fn(() => userQuery)
        };

        userService = new UserService(userModel);
    });

    afterEach(() => {
        expect(userModel.find).toHaveBeenCalled();
        expect(userQuery.select).toHaveBeenCalledWith('name');
    });

    it('should get the user names', async () => {
        const users = [{
            name: 'john'
        }, {
            name: 'jane'
        }];
        userQuery.select.mockImplementation(() => Promise.resolve(users));

        await expect(userService.getAll()).resolves.toBe(users);
    });

    it('should handle errors', async () => {
        const error = new Error('Fake model error');
        userQuery.select.mockImplementation(() => Promise.reject(error));

        await expect(userService.getAll()).rejects.toMatch({
            status: 500,
            message: 'Error while fetching users.',
            cause: error
        });
    });
});

此代码未经测试,因此可能无法正常工作,但希望它充分概述了这个想法。

<小时/>

虽然这与您的问题没有直接关系,但我会避免将 async/await 与传统的 Promise 处理混合在一起。

public async getAll() {
    try {
        return <[IUser]> await this.userModel.find().select('name');
    } catch (e) {
        throw new HttpException(500, 'Error while fetching users.', e)
    }
}

关于javascript - 开 Jest : How to properly test a Javascript service using MongoDB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60178564/

相关文章:

java - 我如何在 JMockit 中期望和验证相同的方法

c# - MS 测试,试图将我的测试名称插入到测试功能中

javascript - Swiper 禁用左右半/部分滑动

javascript - 打印弹出窗口Javascript

node.js - 无法使用express框架创建数据然后将数据保存到mongodb中(现在可以使用。)

javascript - 使用 MEAN 堆栈查询关联模型

java - 如何在 java 中使用 $lookup stage 和 spring data mongodb?

javascript 函数被调用两次

javascript - 从头开始在最后添加下划线

testing - JIRA:如何让搜索框记住项目代码?