我是 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;
}
我想测试一下这个功能。以下是我可以运行的测试:
- 调用路由,并检查生成的 JSON 是否正确
- 获取数据库内容,并检查其是否符合预期
- 只需测试
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/