我是Jest的初学者。

我有一个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;
}


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


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


我认为1和2很明显,并且涵盖了不同的内容。 1覆盖请求部分,2覆盖DB部分。但是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 is undefined

我还应该嘲笑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)
    }
}

09-25 18:30
查看更多