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

如何在Jest单元测试中测试inquirer.prompt的validate与filter函数

问题

我在单元测试中尝试mock inquirer.prompt方法,该方法包含多个问题(示例仅展示两个),代码如下:

return prompt([
{
    type: 'input',
    name: 'name1',
    message: 'Question 1?',
    filter: (fieldValue: string) => fieldValue.trim(),
    validate: (fieldValue: string) => showValidationResults(fieldValue, validateFieldIsNotEmpty),
},
{
    type: 'input',
    name: 'name2',
    message: 'Question 2?',
    validate: (fieldValue: string) => showValidationResults(fieldValue, validateFieldIsNotEmpty),
},
...
]);

我需要达到指定单元测试覆盖率,因此希望检查filter和validate函数是否被正确调用。现有方案建议将这些函数提取为独立方法后直接测试,但这无法确认filter和validate代码行是否被调用,还会降低代码简洁性。另外,我不想直接调用私有方法,更倾向于调用类的主方法。请问是否可以mock prompt并注入问题答案,同时验证filter和validate部分是否已执行?

解决方案

完全可以通过mock inquirer.prompt来实现你的需求,不需要拆分函数或者调用私有方法。核心思路是拦截prompt方法,拿到传入的问题配置数组,手动触发其中的filter和validate函数,同时注入模拟的用户输入,最后验证这些函数的调用情况。

以Jest为例,具体步骤如下:

  • Mock inquirer模块
    在测试文件中先mock整个inquirer模块,让prompt方法处于我们的控制之下:

    jest.mock('inquirer');
    import inquirer from 'inquirer';
    import YourClass from './your-class-path';
    
  • 拦截prompt调用并验证函数执行
    在测试用例中,重写prompt的mock实现,捕获传入的问题列表,针对每个问题的filter和validate做验证:

    test('验证filter和validate函数被正确触发', async () => {
      // 模拟用户输入的答案
      const mockAnswers = { name1: '  test input  ', name2: 'valid input' };
      const yourClassInstance = new YourClass();
    
      // 重写prompt的mock逻辑
      (inquirer.prompt as jest.Mock).mockImplementation(async (questions) => {
        // 遍历问题列表,逐个验证filter和validate
        questions.forEach(question => {
          const inputValue = mockAnswers[question.name];
          if (question.filter) {
            // 执行filter并验证结果
            const filtered = question.filter(inputValue);
            expect(filtered).toBe(inputValue.trim()); // 验证name1的trim处理生效
          }
          if (question.validate) {
            // 执行validate并验证返回值
            const validateResult = question.validate(inputValue);
            expect(validateResult).toBe(true); // 假设验证通过时返回true
          }
        });
        return mockAnswers;
      });
    
      // 调用类的主方法,触发整个流程
      await yourClassInstance.mainMethod();
    
      // 确认prompt确实被调用过
      expect(inquirer.prompt).toHaveBeenCalled();
    });
    
  • 验证异常场景
    如果要测试validate在输入不合法时的行为,只需传入无效模拟输入,断言验证结果符合预期:

    test('验证validate在输入为空时返回错误信息', async () => {
      const invalidAnswers = { name2: '' };
      const yourClassInstance = new YourClass();
    
      (inquirer.prompt as jest.Mock).mockImplementation(async (questions) => {
        const name2Question = questions.find(q => q.name === 'name2');
        if (name2Question?.validate) {
          const validateResult = name2Question.validate(invalidAnswers.name2);
          expect(validateResult).toBe('输入不能为空'); // 匹配你的错误提示
        }
        return invalidAnswers;
      });
    
      await yourClassInstance.mainMethod();
    });
    

这种方式既保留了原代码的简洁性,又不需要调用私有方法,完全通过触发类的主方法来覆盖流程,同时能精准验证filter和validate的执行情况,满足覆盖率要求。

内容的提问来源于stack exchange,提问作者mardo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:15:29