You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
        });
    });
解决方案

核心问题

测试失败的原因有两个:

  1. 模块导入路径不匹配,导致mock的queries模块和passport.js中实际依赖的不是同一个
  2. 测试文件未正确导入要测试的verifyCallback函数

修复步骤

  1. 修正queries模块的导入路径
    passport.js中使用require('../../../../db/queries'),而测试文件中是import queries from '../../db/queries',路径层级差异导致mock失效。需要将测试文件的queries导入路径调整为和passport.js一致:

    import queries from '../../../../db/queries';
    
  2. 导入verifyCallback函数
    测试文件中缺少对verifyCallback的导入,需从passport.js文件中引入:

    import { verifyCallback } from '../path/to/passport';
    

    注意替换../path/to/passport为实际的相对路径。

  3. 确认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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 04:00:34