如何用Jest测试GraphQL Resolver?无需连接数据库的测试方案
如何用Jest测试MongoDB+Mongoose的GraphQL只读Resolver(无需连接真实数据库)
别担心,我来一步步带你搞定这个测试——核心就是Mock掉Mongoose的Article模型方法,让它返回我们预设的测试数据,完全不用碰真实数据库。下面是具体步骤:
1. 准备测试环境并Mock模型
首先,在你的测试文件(比如resolvers.test.js)里,用Jest替换掉真实的Mongoose Article模型。假设你的模型文件路径是../models/Article,代码如下:
// 用Mock版本替换真实的Article模型 jest.mock('../models/Article'); // 导入Mock后的模型和你的Resolver const Article = require('../models/Article'); const { Query } = require('../resolvers');
接下来我们要给Mock的Article添加模拟的find和findById方法,让它们返回预设的Promise数据。
2. 测试articles查询Resolver
这个Resolver调用了Article.find(),我们需要验证两点:它正确调用了模型方法,并且返回预期的文章列表。
describe('Query.articles', () => { it('should return a list of articles successfully', async () => { // 预设模拟返回的测试数据 const mockArticles = [ { _id: '1', title: 'Test Article 1', authors: [] }, { _id: '2', title: 'Test Article 2', authors: [] } ]; // 让Article.find返回一个resolve到mockArticles的Promise Article.find.mockImplementationOnce(() => Promise.resolve(mockArticles) ); // 调用Resolver const result = await Query.articles(); // 验证结果是否符合预期 expect(result).toEqual(mockArticles); // 验证Article.find是否被正确调用(参数为空对象,第二个参数是回调函数) expect(Article.find).toHaveBeenCalledWith({}, expect.any(Function)); }); it('should reject with error when database query fails', async () => { // 预设模拟的错误信息 const mockError = new Error('Database connection failed'); Article.find.mockImplementationOnce(() => Promise.reject(mockError) ); // 验证Resolver是否正确抛出错误 await expect(Query.articles()).rejects.toThrow(mockError); }); });
3. 测试article查询Resolver
这个Resolver调用了Article.findById(_id),我们需要验证:它用传入的_id正确调用模型方法、返回对应文章,以及错误场景下的处理逻辑。
describe('Query.article', () => { it('should return a single article by _id', async () => { const mockArticle = { _id: '1', title: 'Test Article', authors: [] }; const testId = '1'; // 让findById根据传入的id返回对应数据 Article.findById.mockImplementationOnce((id) => Promise.resolve(id === testId ? mockArticle : null) ); // 调用Resolver,传入参数 const result = await Query.article(null, { _id: testId }); expect(result).toEqual(mockArticle); // 验证findById是否用正确的_id调用 expect(Article.findById).toHaveBeenCalledWith(testId, expect.any(Function)); }); it('should return null when target article does not exist', async () => { const testId = 'non-existent-id'; Article.findById.mockImplementationOnce(() => Promise.resolve(null)); const result = await Query.article(null, { _id: testId }); expect(result).toBeNull(); }); it('should reject with error when findById operation fails', async () => { const mockError = new Error('Failed to fetch article'); Article.findById.mockImplementationOnce(() => Promise.reject(mockError)); await expect(Query.article(null, { _id: '1' })).rejects.toThrow(mockError); }); });
关键说明
- 我们用
jest.mock完全替换了真实的Mongoose模型,所以测试全程不会连接任何数据库,所有数据都是我们预设的模拟值。 mockImplementationOnce可以让每个测试用例的模拟逻辑独立,避免不同测试之间互相干扰。- 虽然你的Resolver里用了回调式的Mongoose方法,但我们直接返回Promise是完全可行的,Jest会自动处理异步操作的断言。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

