Vitest中如何模拟函数依赖?我的测试为何失败?
问题:测试Passport.js的verifyCallback时无法模拟getUser依赖
我尝试模拟passport.js代码片段中依赖的getUser和createAndReturnUser函数,但未成功。测试失败且实际调用了getUser函数并抛出错误。以下是我的代码:
passport.js
const {getUser, createAndReturnUser} = require('../../../../db/queries'); const verifyCallback = async (accessToken, refreshToken, profile, cb) => { // Check if user exists (Find or Create) try { const responseUser = await getUser(profile.id, profile.provider); console.log('Response user',responseUser); if (responseUser) { return cb(null, responseUser); } else { const newUser = await createAndReturnUser( profile.id, profile.displayName, profile.name.givenName, profile.name.middleName, profile.name.familyName, profile.emails[0].value, profile.photos[0].value, profile.provider, accessToken, refreshToken ) return cb(null, newUser); } } catch (err) { return cb(err); } }
passport.test.js
import { describe, expect, it, vi } from 'vitest'; import queries from '../../db/queries'; vi.mock('../../db/queries'); describe('verifyCallback() functionality', () => { it('should verify an existing user', async () => { const accessToken = '1234'; const refreshToken = '1234'; const profile = { id: '12345', displayName: 'Fake Tech Exec', name: { givenName: 'Fake', middleName: 'Tech', familyName: 'Exec' }, emails: [{ value: 'faketech@test.com' }], photos: [{ value: 'https:faketechexec.jpg' }], provider: 'facebook', }; const cb = vi.fn(); const user = { id: '12345', displayName: 'fakeTechExec', firstName: 'fake', middleName: 'Tech', lastName: 'Exec', profilePicture: 'faketechexec.jpg' } queries.getUser.mockResolvedValue(user) await verifyCallback(accessToken, refreshToken, profile, cb); expect(cb).toBeCalled(); expect(cb).toBeCalledWith(null, user); }); });
解决方案
核心问题
测试失败的原因有两个:
- 模块导入路径不匹配,导致mock的
queries模块和passport.js中实际依赖的不是同一个 - 测试文件未正确导入要测试的
verifyCallback函数
修复步骤
修正queries模块的导入路径
passport.js中使用require('../../../../db/queries'),而测试文件中是import queries from '../../db/queries',路径层级差异导致mock失效。需要将测试文件的queries导入路径调整为和passport.js一致:import queries from '../../../../db/queries';导入verifyCallback函数
测试文件中缺少对verifyCallback的导入,需从passport.js文件中引入:import { verifyCallback } from '../path/to/passport';注意替换
../path/to/passport为实际的相对路径。确认Vitest配置支持模块交互
如果项目混合使用CommonJS(passport.js用require)和ES模块(测试用import),需在vitest.config.js中确保Node环境配置:export default { test: { environment: 'node', }, }
修正后的测试文件示例
import { describe, expect, it, vi } from 'vitest'; import queries from '../../../../db/queries'; import { verifyCallback } from '../path/to/passport'; vi.mock('../../../../db/queries'); describe('verifyCallback() functionality', () => { it('should verify an existing user', async () => { const accessToken = '1234'; const refreshToken = '1234'; const profile = { id: '12345', displayName: 'Fake Tech Exec', name: { givenName: 'Fake', middleName: 'Tech', familyName: 'Exec' }, emails: [{ value: 'faketech@test.com' }], photos: [{ value: 'https:faketechexec.jpg' }], provider: 'facebook', }; const cb = vi.fn(); const user = { id: '12345', displayName: 'fakeTechExec', firstName: 'fake', middleName: 'Tech', lastName: 'Exec', profilePicture: 'faketechexec.jpg' }; queries.getUser.mockResolvedValue(user); await verifyCallback(accessToken, refreshToken, profile, cb); expect(cb).toBeCalled(); expect(cb).toBeCalledWith(null, user); }); });
额外测试建议
可以补充用户不存在的场景测试,模拟createAndReturnUser的返回值,验证回调是否正确传入新创建的用户:
it('should create and return a new user when none exists', async () => { const accessToken = '1234'; const refreshToken = '1234'; const profile = { /* 同之前的profile数据 */ }; const cb = vi.fn(); queries.getUser.mockResolvedValue(null); const newUser = { id: '67890', displayName: 'New User' }; queries.createAndReturnUser.mockResolvedValue(newUser); await verifyCallback(accessToken, refreshToken, profile, cb); expect(cb).toBeCalledWith(null, newUser); expect(queries.createAndReturnUser).toBeCalledWith( profile.id, profile.displayName, profile.name.givenName, profile.name.middleName, profile.name.familyName, profile.emails[0].value, profile.photos[0].value, profile.provider, accessToken, refreshToken ); });
内容的提问来源于stack exchange,提问作者Mike Guijarro
相关产品推荐
相关产品推荐

