datai/datai-scenes/datai-scene-salesforce/docs/prompts/2026-02-02-002-03-prompt-测试执行.md

11 KiB
Raw Permalink Blame History

提示词:测试执行功能

引用真源

需求描述

根据需求文档,实现 Apex 测试执行功能,包括:

  1. 运行所有测试runAllTests
  2. 运行指定类的测试runTestsByClasses
  3. 运行指定包的测试runTestsByPackages
  4. 运行指定测试方法runTestsByMethods
  5. 查询测试结果queryTestResults
  6. 查询测试详情queryTestDetails
  7. 查询代码覆盖率queryCodeCoverage
  8. 查询 Flow 覆盖率queryFlowCoverage

设计方案

根据设计文档,采用以下技术方案:

  1. 连接管理:复用 ApexConnectionFactory 获取 SoapConnection
  2. 并发控制:使用 ReentrantLock 保证多线程安全
  3. 事务管理:使用 @Transactional 保证数据一致性
  4. 数据存储
    • 复用 002-02 的表datai_apex_test_result、datai_apex_test_failure、datai_apex_code_coverage
    • 新建表datai_apex_test_success、datai_apex_flow_coverage
  5. API 集成:使用 apex.jar 中的 SoapConnection.runTests() 方法
  6. 权限控制:使用 @PreAuthorize("@ss.hasPermi('apex:test:execute')") 进行权限控制

输出格式要求

1. 必须包含以下文件

Controller 层

  • ApexTestController.java(路径:datai-salesforce-apex/src/main/java/com/datai/apex/controller/ApexTestController.java
    • 运行所有测试接口
    • 运行指定类测试接口
    • 运行指定包测试接口
    • 运行指定方法测试接口
    • 查询测试结果接口
    • 查询测试详情接口
    • 查询代码覆盖率接口
    • 查询 Flow 覆盖率接口

Service 层

  • IApexTestService.java(路径:datai-salesforce-apex/src/main/java/com/datai/apex/service/IApexTestService.java
    • 定义测试执行相关接口方法
  • ApexTestServiceImpl.java(路径:datai-salesforce-apex/src/main/java/com/datai/apex/service/impl/ApexTestServiceImpl.java
    • 实现测试执行逻辑
    • 使用 ReentrantLock 保证线程安全
    • 保存测试结果到数据库

DTO 层

  • RunAllTestsDto.java - 运行所有测试请求参数
  • RunTestsByClassesDto.java - 运行指定类测试请求参数
  • RunTestsByPackagesDto.java - 运行指定包测试请求参数
  • RunTestsByMethodsDto.java - 运行指定方法测试请求参数
  • TestsNodeDto.java - 测试节点 DTO
  • QueryTestResultsDto.java - 查询测试结果请求参数
  • QueryTestDetailsDto.java - 查询测试详情请求参数
  • QueryCodeCoverageDto.java - 查询代码覆盖率请求参数
  • QueryFlowCoverageDto.java - 查询 Flow 覆盖率请求参数

VO 层

  • RunTestsResultVo.java - 测试结果 VO
  • RunTestSuccessVo.java - 测试成功详情 VO
  • RunTestFailureVo.java - 测试失败详情 VO
  • CodeCoverageResultVo.java - 代码覆盖率结果 VO
  • FlowCoverageResultVo.java - Flow 覆盖率结果 VO
  • TestResultSummaryVo.java - 测试结果摘要 VO
  • TestDetailVo.java - 测试详情 VO

Entity 层(新建)

  • DataiApexTestSuccess.java - 测试成功详情实体
  • DataiApexFlowCoverage.java - Flow 覆盖率实体

Mapper 层(新建)

  • DataiApexTestSuccessMapper.java - 测试成功详情 Mapper 接口
  • DataiApexTestSuccessMapper.xml - 测试成功详情 Mapper XML
  • DataiApexFlowCoverageMapper.java - Flow 覆盖率 Mapper 接口
  • DataiApexFlowCoverageMapper.xml - Flow 覆盖率 Mapper XML

2. 代码结构要求

datai-salesforce-apex/src/main/java/com/datai/apex/
├── controller/
│   └── ApexTestController.java
├── service/
│   ├── IApexTestService.java
│   └── impl/
│       └── ApexTestServiceImpl.java
├── dto/
│   ├── RunAllTestsDto.java
│   ├── RunTestsByClassesDto.java
│   ├── RunTestsByPackagesDto.java
│   ├── RunTestsByMethodsDto.java
│   ├── TestsNodeDto.java
│   ├── QueryTestResultsDto.java
│   ├── QueryTestDetailsDto.java
│   ├── QueryCodeCoverageDto.java
│   └── QueryFlowCoverageDto.java
├── vo/
│   ├── RunTestsResultVo.java
│   ├── RunTestSuccessVo.java
│   ├── RunTestFailureVo.java
│   ├── CodeCoverageResultVo.java
│   ├── FlowCoverageResultVo.java
│   ├── TestResultSummaryVo.java
│   └── TestDetailVo.java
├── domain/
│   ├── DataiApexTestSuccess.java
│   └── DataiApexFlowCoverage.java
└── mapper/
    ├── DataiApexTestSuccessMapper.java
    └── DataiApexFlowCoverageMapper.java

datai-salesforce-apex/src/main/resources/mapper/apex/
├── DataiApexTestSuccessMapper.xml
└── DataiApexFlowCoverageMapper.xml

代码规范要求

1. 命名规范

  • 类命名:首字母大写,驼峰命名,如 ApexTestController
  • 方法命名:首字母小写,驼峰命名,如 runAllTests
  • 变量命名:首字母小写,驼峰命名,如 testResult
  • 常量命名:全大写,下划线分隔,如 DEFAULT_MAX_FAILED_TESTS

2. 注释规范

  • 类注释:使用 /** */,包含类功能描述、作者、创建时间
  • 方法注释:使用 /** */,包含方法功能、参数、返回值、异常描述
  • 字段注释:使用 /** */,包含字段功能描述

3. 代码格式

  • 使用 4 个空格缩进
  • 行宽不超过 120 字符
  • 导入规范:使用 import 静态导入,避免通配符导入

4. 异常处理

  • 使用 try-catch-finally 块确保锁的释放
  • 捕获 SalesforceAuthException 并直接抛出
  • 捕获其他异常并包装为 SalesforceOperationException
  • 使用 log 记录异常信息

5. 数据库操作

  • 使用 MyBatis 进行数据库操作(不使用 MyBatis Plus
  • Mapper 方法命名insertXxx、updateXxx、deleteXxx、selectXxx
  • XML 中编写 SQL 语句,使用参数绑定

6. 事务管理

  • 在 Service 实现类上使用 @Transactional(rollbackFor = Exception.class)
  • 确保数据库操作的原子性

7. 权限控制

  • Controller 方法使用 @PreAuthorize("@ss.hasPermi('apex:test:execute')") 进行权限控制
  • 查询接口使用 @PreAuthorize("@ss.hasPermi('apex:test:query')") 进行权限控制

8. 日志记录

  • 使用 Lombok 的 @Slf4j 注解
  • 关键操作记录 info 级别日志
  • 异常记录 error 级别日志
  • 使用占位符 {} 而不是字符串拼接

核心实现逻辑

1. 运行测试流程

@Override
@Transactional(rollbackFor = Exception.class)
public RunTestsResultVo runTests(RunTestsRequestDto dto) throws SalesforceAuthException, SalesforceOperationException {
    lock.lock();
    try {
        // 1. 构建 RunTestsRequest
        RunTestsRequest request = buildRunTestsRequest(dto);
        
        // 2. 获取 SoapConnection
        SoapConnection connection = apexConnectionFactory.getConnection("source");
        
        // 3. 执行测试
        RunTestsResult result = connection.runTests(request);
        
        // 4. 保存测试结果
        saveTestResults(result);
        
        // 5. 转换为 VO 并返回
        return convertToVo(result);
        
    } catch (SalesforceAuthException e) {
        throw e;
    } catch (Exception e) {
        throw new SalesforceOperationException("运行测试失败: " + e.getMessage(), e);
    } finally {
        lock.unlock();
    }
}

2. 保存测试结果

private void saveTestResults(RunTestsResult result) {
    // 1. 保存测试结果主表
    DataiApexTestResult testResult = new DataiApexTestResult();
    testResult.setTestRunId(result.getApexLogId());
    testResult.setNumTestsRun(result.getNumTestsRun());
    testResult.setNumFailures(result.getNumFailures());
    testResult.setTotalTime(result.getTotalTime());
    testResult.setApexLogId(result.getApexLogId());
    testResult.setTestTime(new Date());
    testResult.setAllPassed(result.getNumFailures() == 0);
    testResult.setTotalCoverage(calculateTotalCoverage(result.getCodeCoverage()));
    testResultMapper.insertDataiApexTestResult(testResult);
    
    // 2. 保存测试成功详情
    if (result.getSuccesses() != null) {
        for (RunTestSuccess success : result.getSuccesses()) {
            DataiApexTestSuccess testSuccess = convertToTestSuccess(success, testResult.getId());
            testSuccessMapper.insertDataiApexTestSuccess(testSuccess);
        }
    }
    
    // 3. 保存测试失败详情
    if (result.getFailures() != null) {
        for (RunTestFailure failure : result.getFailures()) {
            DataiApexTestFailure testFailure = convertToTestFailure(failure, testResult.getId());
            testFailureMapper.insertDataiApexTestFailure(testFailure);
        }
    }
    
    // 4. 保存代码覆盖率
    if (result.getCodeCoverage() != null) {
        for (CodeCoverageResult coverage : result.getCodeCoverage()) {
            DataiApexCodeCoverage codeCoverage = convertToCodeCoverage(coverage, testResult.getId());
            codeCoverageMapper.insertDataiApexCodeCoverage(codeCoverage);
        }
    }
    
    // 5. 保存 Flow 覆盖率
    if (result.getFlowCoverage() != null) {
        for (FlowCoverageResult flowCoverage : result.getFlowCoverage()) {
            DataiApexFlowCoverage flowCoverageEntity = convertToFlowCoverage(flowCoverage, testResult.getId());
            flowCoverageMapper.insertDataiApexFlowCoverage(flowCoverageEntity);
        }
    }
}

3. 覆盖率计算

private double calculateTotalCoverage(CodeCoverageResult[] coverages) {
    if (coverages == null || coverages.length == 0) {
        return 0.0;
    }
    
    int totalLocations = 0;
    int totalNotCovered = 0;
    
    for (CodeCoverageResult coverage : coverages) {
        totalLocations += coverage.getNumLocations();
        totalNotCovered += coverage.getNumLocationsNotCovered();
    }
    
    if (totalLocations == 0) {
        return 0.0;
    }
    
    return (1.0 - (double) totalNotCovered / totalLocations) * 100;
}

注意事项

  1. 复用已有组件

    • 使用 ApexConnectionFactory 获取连接(来自 002-01
    • 复用 datai_apex_test_result、datai_apex_test_failure、datai_apex_code_coverage 表(来自 002-02
  2. 正确处理 Salesforce API

    • 使用 apex.jar 中的原生类RunTestsRequest、RunTestsResult、RunTestSuccess、RunTestFailure、CodeCoverageResult、FlowCoverageResult
    • 正确处理空值情况
    • 注意数组可能为 null
  3. 数据一致性

    • 使用 @Transactional 保证事务
    • 使用 ReentrantLock 保证并发安全
    • 确保 finally 块中释放锁
  4. 性能优化

    • 批量插入数据
    • 使用索引加速查询
    • 避免 N+1 查询问题
  5. 异常处理

    • 区分 SalesforceAuthException 和 SalesforceOperationException
    • 记录详细的错误日志
    • 提供有意义的错误消息
  6. 代码生成前置条件检查

    • 确认需求文档已创建
    • 确认设计文档已创建
    • 确认 ADR 决策记录已创建
    • 确认 SQL 脚本已创建
    • 确认本提示词文档已创建