【项目】智能AI面试官平台 测试报告


一、项目背景

项目介绍

InterviewGuide 是一个集成了简历分析、模拟面试和知识库管理的智能面试辅助平台。系统利用大语言模型(LLM)和向量数据库技术(pgvector),为求职者和 HR 提供智能化的简历评估和面试练习服务。

区别于传统的面试准备方式,用户只需上传简历,系统就能利用 AI 自动分析简历内容智能生成面试题目模拟真实面试场景并给出多维度评估报告,实现面试准备的降本增效。

问题分析

传统面试准备存在以下痛点:

  1. 简历优化依赖主观经验,缺乏专业反馈
  2. 面试练习缺少真实场景模拟,无法获得即时追问
  3. 面试表现评估不够客观,缺少多维度量化指标
  4. 知识储备分散,无法快速检索和利用

技术栈

后端技术:

技术 版本 说明
Spring Boot 4.0 应用框架
Java 21 开发语言
Spring AI 2.0 AI 集成框架
PostgreSQL + pgvector 14+ 关系数据库 + 向量存储
Redis 6+ 缓存 + 消息队列(Stream)
Apache Tika 2.9.2 文档解析
iText 8 8.0.5 PDF 导出

前端技术:

技术 版本 说明
React 18.3 UI 框架
TypeScript 5.6 开发语言
Vite 5.4 构建工具
Tailwind CSS 4.1 样式框架

二、项目功能

  1. 简历管理:支持 PDF、DOCX、DOC、TXT 等多格式简历上传,基于 Redis Stream 异步 AI 分析,支持分析报告 PDF 导出
  2. 模拟面试:基于简历内容智能生成面试题目,支持实时问答与智能追问,采用分批评估策略,生成多维度评估报告
  3. 知识库管理:支持多格式文档上传与自动向量化,基于 RAG 检索增强的智能问答,SSE 流式响应
  4. 历史记录:简历分析历史与面试历史的查看与管理

异步处理流程:

上传请求 → 保存文件 → 发送消息到 Redis Stream → 立即返回
                              ↓
                      Consumer 消费消息
                              ↓
                    执行分析/向量化/评估任务
                              ↓
                      更新数据库状态
                              ↓
                   前端轮询获取最新状态

状态流转:PENDINGPROCESSINGCOMPLETED / FAILED


三、功能测试

软件环境:

项目 版本
操作系统 Windows 11
浏览器 Google Chrome 131.0.6778.205
数据库 PostgreSQL 14 + pgvector
缓存 Redis 6+
JDK 21
Node.js 18+

测试用例总览:
在这里插入图片描述


1、简历上传测试

测试用例
编号 测试项 前置条件 测试步骤 输入数据 预期结果 优先级
R-01 上传PDF简历 已登录 进入上传页面,选择PDF文件,点击上传 有效PDF简历 上传成功,状态显示PENDING P0
R-02 上传DOCX简历 已登录 进入上传页面,选择DOCX文件,点击上传 有效DOCX简历 上传成功,状态显示PENDING P0
R-03 上传DOC简历 已登录 进入上传页面,选择DOC文件,点击上传 有效DOC简历 上传成功,状态显示PENDING P0
R-04 上传TXT简历 已登录 进入上传页面,选择TXT文件,点击上传 有效TXT简历 上传成功,状态显示PENDING P1
R-05 上传JPG图片 已登录 选择JPG文件上传 .jpg文件 提示文件格式不支持 P1
R-06 上传EXE文件 已登录 选择EXE文件上传 .exe文件 提示文件格式不支持 P1
R-07 上传空文件 已登录 选择空文件上传 0KB文件 提示文件内容为空 P1
R-08 上传超大文件 已登录 选择超出限制的文件上传 超大文件 提示文件大小超出限制 P2
R-09 不选文件直接提交 已登录 不选择文件,直接点击上传按钮 提示请选择文件 P1
R-10 重复上传相同简历 已上传过一份简历 再次上传相同内容的简历 已分析过的文件 提示简历已存在(哈希检测) P1
测试结果

1. 上传页面展示

在这里插入图片描述

2. 正常上传(PDF简历)

在这里插入图片描述

3. 异常上传 — 不支持的文件格式

在这里插入图片描述

4. 异常上传 — 重复上传

多次上传结果不变


2、简历异步分析测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
RA-01 PENDING状态显示 刚上传简历 观察页面状态 显示"待分析" P0
RA-02 PROCESSING状态显示 简历进入分析队列 观察页面状态变化 显示"分析中" P0
RA-03 COMPLETED状态显示 分析完成 观察页面状态变化 显示"已完成" P0
RA-04 FAILED状态显示 分析失败 观察页面状态变化 显示"分析失败" P0
RA-05 分析结果查看 分析完成 点击查看分析结果 显示AI分析内容,内容合理 P0
RA-06 自动重试机制 AI服务临时异常 观察后端日志 自动重试最多3次 P1
RA-07 前端轮询状态刷新 简历在分析中 等待分析完成 页面自动更新为最新状态 P1
RA-08 AI服务不可用 AI API Key无效 上传简历触发分析 状态变为FAILED P1
RA-09 Redis服务异常 Redis连接中断 上传简历 给出合理错误提示 P2
测试结果

1. 分析完成结果展示

在这里插入图片描述

2. 分析失败情况

在这里插入图片描述


3、简历分析详情与PDF导出测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
RD-01 查看已完成分析详情 分析状态COMPLETED 点击简历查看详情 显示完整分析报告 P0
RD-02 查看分析中简历详情 分析状态PROCESSING 点击简历查看详情 显示加载/进度状态 P1
RD-03 查看分析失败详情 分析状态FAILED 点击简历查看详情 显示失败原因 P1
测试结果

1. 简历分析详情页

在这里插入图片描述

2. 分析失败结果

在这里插入图片描述


4、创建面试测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
IC-01 正常创建面试 有已分析完成的简历 选择简历,点击创建面试 创建成功,AI生成面试题目 P0
IC-02 题目与简历相关性 面试创建成功 检查生成的题目内容 题目与简历技能/经历相关 P0
IC-03 不选简历创建 未选择简历 直接点击创建面试 提示请选择简历 P1
IC-04 选择未完成分析的简历 简历分析中 选择该简历创建面试 提示简历分析未完成 P1
测试结果

1. 正常创建面试

在这里插入图片描述

2. 异常创建

在这里插入图片描述


5、面试问答交互测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
IQ-01 正常回答问题 面试进行中 输入回答内容,点击提交 AI接收回答,显示下一题或追问 P0
IQ-02 智能追问触发 回答一个问题后 观察AI是否追问 生成1条追问(默认配置) P0
IQ-03 多轮对话连贯性 已进行多轮对话 检查追问内容 追问与前面回答上下文相关 P0
IQ-04 完成所有问题 回答到最后一题 提交最后一个回答 面试正常结束,进入评估 P0
IQ-05 提交空白回答 面试进行中 不输入内容直接提交 提示请输入回答内容 P1
IQ-06 超长文本回答 面试进行中 输入大量文本提交 正常处理或给出长度限制提示 P2
IQ-07 刷新页面恢复会话 面试进行中 按F5刷新页面 面试会话从Redis恢复,继续面试 P1
IQ-08 网络断开重连 面试进行中 断开网络后重连 面试状态不丢失 P2
测试结果

1. 正常问答交互

在这里插入图片描述

2. 智能追问效果

在这里插入图片描述

6、面试评估与报告测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
IE-01 单批评估(<8题) 面试回答<8条 完成面试触发评估 评估正常完成 P0
IE-02 分批评估(>8题) 面试回答>8条 完成面试触发评估 分批评估正常,无Token溢出 P0
IE-03 评估结果汇总 评估完成 查看评估结论 包含改进建议、表现趋势、统计 P0
IE-04 评估状态流转 面试结束 观察状态变化 PENDING → PROCESSING → COMPLETED P0
IE-05 PDF报告导出 评估完成 点击导出报告 PDF下载成功 P0
IE-06 报告内容完整性 导出PDF 打开检查内容 包含所有问答记录和评估结论 P0
IE-07 面试未完成时导出 面试进行中 点击导出报告 提示面试未结束 P1
IE-08 评估进行中导出 评估PROCESSING 点击导出报告 提示评估进行中 P1
测试结果

1. 评估结果展示

在这里插入图片描述

2. PDF面试报告

在这里插入图片描述


7、面试历史页面测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
IH-01 有记录时列表展示 有面试记录 进入面试历史页面 正确显示面试历史列表 P0
IH-02 无记录时页面展示 无面试记录 进入面试历史页面 显示空状态提示 P1
IH-03 查看面试详情 有面试记录 点击某条面试记录 进入详情页,显示完整问答记录 P0
测试结果

1. 面试历史列表

在这里插入图片描述

2. 无记录时展示

在这里插入图片描述


8、知识库文档上传测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
KU-01 上传PDF文档 已登录 选择PDF文档上传 上传成功,状态PENDING P0
KU-02 上传DOCX文档 已登录 选择DOCX文档上传 上传成功 P0
KU-03 上传Markdown文档 已登录 选择MD文件上传 上传成功 P0
KU-04 上传不支持格式 已登录 选择.jpg文件上传 提示格式不支持 P1
KU-05 上传空文件 已登录 选择空文件上传 提示文件为空 P1
KU-06 上传超大文件 已登录 选择超大文件上传 提示大小超限 P2
测试结果

1. 正常上传

在这里插入图片描述

2. 异常上传

在这里插入图片描述


9、知识库向量化测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
KV-01 PENDING状态显示 刚上传文档 查看状态 显示"待处理" P0
KV-02 PROCESSING状态显示 向量化进行中 查看状态 显示"处理中" P0
KV-03 COMPLETED状态显示 向量化完成 查看状态 显示"已完成" P0
KV-04 FAILED状态显示 向量化失败 查看状态 显示"处理失败" P0
KV-05 文档自动分块 向量化完成 检查数据库 文档被合理分块 P1
KV-06 向量存储验证 向量化完成 查询pgvector 有对应向量数据 P1
测试结果

1. 向量化展示

在这里插入图片描述


10、RAG智能问答测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
RQ-01 基于知识库提问 知识库有已向量化文档 输入相关问题 AI回答与知识库内容相关 P0
RQ-02 SSE流式响应 正常提问 观察回答显示方式 打字机效果逐字显示 P0
RQ-03 多轮对话 已进行一轮问答 继续提问 上下文连贯 P0
RQ-04 知识库为空时提问 知识库无文档 输入问题 合理提示或通用回答 P1
RQ-05 无关问题 知识库有文档 提问与知识库无关的问题 AI合理回复 P1
RQ-06 空内容发送 在问答页面 不输入内容点击发送 提示请输入问题 P1
RQ-07 网络中断流式响应 流式响应中 断开网络 合理处理中断 P2
测试结果

1. RAG问答效果

在这里插入图片描述

2. 多轮对话

在这里插入图片描述


11、知识库管理页面测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
KM-01 知识库列表展示 有已上传文档 进入管理页面 正确展示所有文档 P0
KM-02 知识库统计信息 有文档数据 查看统计区域 显示文档数量等统计 P1
KM-03 文档下载功能 有已上传文档 点击下载按钮 文件下载成功 P1
测试结果

1. 知识库管理页面

在这里插入图片描述


12、简历历史页面测试

测试用例
编号 测试项 前置条件 测试步骤 预期结果 优先级
RH-01 有记录时列表展示 有简历记录 进入简历历史页面 正确显示简历列表 P0
RH-02 无记录时页面展示 无简历记录 进入简历历史页面 显示空状态提示 P1
RH-03 各状态简历标识 有不同状态的简历 查看列表 不同状态有对应标识 P1
RH-04 点击查看详情 有简历记录 点击某条记录 跳转到分析详情页 P0
RH-05 列表分页功能 简历数量较多 点击下一页 翻页正常 P2
测试结果

1. 简历历史列表

在这里插入图片描述

2. 无记录展示

在这里插入图片描述


四、自动化测试

整体架构模式

采用 JUnit 5 + Mockito + Spring Boot Test 进行后端自动化测试,按模块组织测试类:

app/src/test/java/interview/guide/
├── AppTest.java                                          # 应用启动测试
├── common/
│   ├── aspect/
│   │   ├── RateLimitScriptTest.java                      # 限流注解单元测试
│   │   └── RateLimitIntegrationTest.java                 # 限流集成测试
│   └── exception/
│       └── RateLimitExceededExceptionTest.java            # 限流异常测试
├── infrastructure/file/
│   ├── DocumentParseServiceTest.java                     # 文档解析服务测试
│   ├── DocumentParseIntegrationTest.java                 # 文档解析集成测试
│   └── TextCleaningServiceTest.java                      # 文本清洗服务测试
└── modules/knowledgebase/service/
    └── KnowledgeBaseVectorServiceTest.java               # 知识库向量服务测试

测试策略:

  • 单元测试:使用 Mockito 隔离外部依赖(VectorStore、Redis 等),专注验证业务逻辑
  • 集成测试:使用真实组件验证端到端流程
  • 参数化测试:通过 @ParameterizedTest 覆盖多种输入场景

运行方式:

# 运行全部测试
./gradlew :app:test

# 运行指定测试类
./gradlew :app:test --tests "interview.guide.modules.knowledgebase.service.KnowledgeBaseVectorServiceTest"

在这里插入图片描述


1、知识库向量服务测试(KnowledgeBaseVectorServiceTest)

本测试类是项目核心测试,覆盖向量化存储、相似度搜索、删除和边界条件四大类场景,共 23 个测试用例

测试点:

分类 测试内容 用例数
向量化存储 基本流程、分批处理(每批<=10)、metadata设置、删旧再存新、异常处理、空内容处理 6
相似度搜索 无过滤搜索、按kb_id过滤(String/Long兼容)、topK限制、搜索失败、空结果、无效kb_id处理 9
删除向量数据 正常删除、删除失败静默处理、删除不存在的数据 3
边界条件 null知识库ID、null内容、空查询、topK为0、topK超过结果数 5

核心测试代码:

@Nested
@DisplayName("向量化存储测试")
class VectorizeAndStoreTests {

    @Test
    @DisplayName("大文本分批处理 - 验证每批不超过限制")
    void testVectorizeLargeContentInBatches() {
        // Given: 生成非常长的文本,确保产生多个 chunks
        Long knowledgeBaseId = 2L;
        String content = generateLongContent(200);

        ArgumentCaptor<List<Document>> captor = ArgumentCaptor.forClass(List.class);

        // When: 执行向量化
        vectorService.vectorizeAndStore(knowledgeBaseId, content);

        // Then: 捕获所有 add 调用,验证每批不超过 10 个(MAX_BATCH_SIZE)
        verify(vectorStore, atLeastOnce()).add(captor.capture());
        List<List<Document>> allBatches = captor.getAllValues();
        for (List<Document> batch : allBatches) {
            assertTrue(batch.size() <= 10,
                "每批次不应超过 10 个文档,实际: " + batch.size());
        }
    }

    @Test
    @DisplayName("验证 metadata 正确设置 kb_id")
    void testMetadataContainsKnowledgeBaseId() {
        Long knowledgeBaseId = 123L;
        String content = generateLongContent(10);
        ArgumentCaptor<List<Document>> captor = ArgumentCaptor.forClass(List.class);

        vectorService.vectorizeAndStore(knowledgeBaseId, content);

        verify(vectorStore, atLeastOnce()).add(captor.capture());
        for (List<Document> batch : captor.getAllValues()) {
            for (Document doc : batch) {
                assertEquals(knowledgeBaseId.toString(), doc.getMetadata().get("kb_id"),
                    "metadata 中的 kb_id 应该等于知识库ID的字符串形式");
            }
        }
    }
}

@Nested
@DisplayName("相似度搜索测试")
class SimilaritySearchTests {

    @Test
    @DisplayName("搜索结果按知识库ID过滤 - String类型kb_id")
    void testSearchWithKnowledgeBaseIdFilterString() {
        String query = "Spring Boot";
        List<Long> knowledgeBaseIds = List.of(1L, 2L);

        // 创建混合的搜索结果
        List<Document> mockResults = new ArrayList<>();
        mockResults.addAll(createMockDocuments(3, "1"));   // 匹配
        mockResults.addAll(createMockDocuments(3, "2"));   // 匹配
        mockResults.addAll(createMockDocuments(4, "3"));   // 应被过滤

        when(vectorStore.similaritySearch(query)).thenReturn(mockResults);

        List<Document> results = vectorService.similaritySearch(query, knowledgeBaseIds, 10);

        // 只返回 kb_id 为 1 或 2 的文档
        assertEquals(6, results.size(), "应该只返回匹配知识库ID的文档");
    }
}

在这里插入图片描述


2、文档解析服务测试(DocumentParseServiceTest)

覆盖简历文件解析的核心逻辑,共 13 个测试用例

测试点:

编号 测试内容 验证方式
1 解析TXT文本文件 验证内容包含关键信息(姓名、技能)
2 解析Markdown文件 验证标题、列表内容被正确解析
3 解析字节数组(带文件名) 验证parseContent(byte[], String)重载
4 解析空文件 验证返回空字符串
5 解析含特殊字符文件 验证emoji、特殊符号不影响解析
6 IO异常处理 验证抛出BusinessException
7 解析中文简历 验证完整中文简历内容提取
8 下载并解析(成功/失败/空内容) 验证downloadAndParseContent流程
9 文本清理服务被调用 验证TextCleaningService集成
10 解析含URL文档 验证URL不被错误清理
11 集成测试-真实文件 使用真实TextCleaningService验证分隔线清理

核心测试代码:

@Test
@DisplayName("集成测试 - 真实文件解析")
void testIntegrationWithRealFile(@TempDir Path tempDir) throws Exception {
    // Given: 创建临时文件
    Path testFile = tempDir.resolve("test-resume.txt");
    String content = """
        张三的简历
        ============
        
        教育背景
        --------
        2015-2019  清华大学  计算机科学与技术  本科
        
        技能清单
        --------
        - 编程语言:Java、Python、Go
        - 数据库:MySQL、PostgreSQL、Redis
        """;
    Files.writeString(testFile, content, StandardCharsets.UTF_8);

    // 使用真实的 TextCleaningService(非Mock)
    TextCleaningService realCleaningService = new TextCleaningService();
    DocumentParseService realService = new DocumentParseService(realCleaningService);

    MultipartFile file = new MockMultipartFile("file", "test-resume.txt",
        "text/plain", Files.readAllBytes(testFile));

    // When
    String result = realService.parseContent(file);

    // Then
    assertNotNull(result);
    assertTrue(result.contains("张三"));
    assertTrue(result.contains("清华大学"));
    assertTrue(result.contains("Spring Boot"));
    // 验证分隔线被清理
    assertFalse(result.contains("============"));
    assertFalse(result.contains("--------"));
}

在这里插入图片描述


3、文本清洗服务测试(TextCleaningServiceTest)

覆盖文本预处理的各种清洗规则,共 17 个测试用例,使用 @ParameterizedTest 参数化测试提高覆盖率。

测试点:

分类 测试内容 用例数
cleanText() 空白内容、清理图片文件名、清理图片URL、清理file协议路径、清理分隔线、清理控制字符、保留换行制表符、统一换行符、压缩连续空行、去除行尾空格、综合清理 10
cleanTextWithLimit() 限制内长度、超限截断、清理后截断、空内容 4
cleanToSingleLine() 多行转单行、压缩空格、混合换行符、空白内容 4
stripHtml() 移除HTML标签、自闭合标签、HTML实体转换、nbsp处理、压缩空格、空白内容、纯文本不变 6

核心测试代码:

@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {"   ", "\n", "\t", "  \n  \t  "})
@DisplayName("空白内容应返回空字符串")
void testBlankContent(String input) {
    String result = textCleaningService.cleanText(input);
    assertEquals("", result);
}

@Test
@DisplayName("综合清理测试")
void testComprehensiveCleaning() {
    String input = """
        个人简历
        ============
        
        姓名:张三
        image001.png
        https://example.com/photo.jpg
        file:///tmp/temp.html
        
        技能:Java
        --------
        """;

    String result = textCleaningService.cleanText(input);

    assertTrue(result.contains("个人简历"));
    assertTrue(result.contains("姓名:张三"));
    assertTrue(result.contains("技能:Java"));
    assertFalse(result.contains("============"));
    assertFalse(result.contains("image001.png"));
    assertFalse(result.contains("https://example.com"));
    assertFalse(result.contains("file:///"));
}

在这里插入图片描述


4、限流功能测试(RateLimitScriptTest + RateLimitExceededExceptionTest)

覆盖 API 限流注解的元数据验证和限流异常的完整性,共 8 个测试用例

测试点:

测试类 测试内容 用例数
RateLimitScriptTest 注解元配置(Retention/Target)、默认值验证、自定义值验证 3
RateLimitExceededExceptionTest 默认构造函数、自定义消息、带原因构造、继承关系、错误码 5

核心测试代码:

@Test
@DisplayName("验证注解默认值")
void testDefaultValues() throws NoSuchMethodException {
    RateLimit ann = TestClass.class.getMethod("defaultMethod").getAnnotation(RateLimit.class);

    assertArrayEquals(new RateLimit.Dimension[]{RateLimit.Dimension.GLOBAL}, ann.dimensions());
    assertEquals(0, ann.timeout());
    assertEquals(1, ann.interval());
    assertEquals(RateLimit.TimeUnit.SECONDS, ann.timeUnit());
    assertEquals("", ann.fallback());
}

@Test
@DisplayName("验证异常继承关系")
void testInheritance() {
    RateLimitExceededException ex = new RateLimitExceededException();
    assertTrue(ex instanceof BusinessException);
    assertTrue(ex instanceof RuntimeException);
}

在这里插入图片描述

自动化测试覆盖模块

模块 覆盖内容 测试框架
知识库向量服务 向量化存储、相似度搜索、分批处理、kb_id过滤、边界条件 JUnit 5 + Mockito
文档解析服务 多格式解析(TXT/MD)、异常处理、文件下载解析 JUnit 5 + Mockito + MockMultipartFile
文本清洗服务 图片/URL清理、HTML处理、控制字符、换行符统一 JUnit 5 + ParameterizedTest
API限流 注解元数据、默认值/自定义值、异常继承关系 JUnit 5

项目地址:GitHub - interview-guide

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐