AI配置增加字段适配处理
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
# Design Document
|
||||
|
||||
## Overview
|
||||
|
||||
本设计文档描述了Coze AI通用接口调用服务的架构设计,以及爽文剧本AI生成功能的实现方案。核心目标是重构AiChatServiceImpl,提供一个通用的、可配置的AI接口调用方法,支持通过config_key获取配置并调用Coze工作流API。
|
||||
|
||||
## Architecture
|
||||
|
||||
### 系统架构图
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "Controller Layer"
|
||||
EC[EpicScriptController]
|
||||
end
|
||||
|
||||
subgraph "Service Layer"
|
||||
ESS[EpicScriptServiceImpl]
|
||||
ACS[AiChatServiceImpl]
|
||||
AICS[AiConfigServiceImpl]
|
||||
end
|
||||
|
||||
subgraph "Data Layer"
|
||||
ACM[AiConfigMapper]
|
||||
ESM[EpicScriptMapper]
|
||||
end
|
||||
|
||||
subgraph "External"
|
||||
COZE[Coze API]
|
||||
end
|
||||
|
||||
EC --> ESS
|
||||
ESS --> ACS
|
||||
ACS --> AICS
|
||||
AICS --> ACM
|
||||
ESS --> ESM
|
||||
ACS --> COZE
|
||||
```
|
||||
|
||||
### 调用流程图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as Controller
|
||||
participant ESS as EpicScriptService
|
||||
participant ACS as AiChatService
|
||||
participant AICS as AiConfigService
|
||||
participant DB as Database
|
||||
participant COZE as Coze API
|
||||
|
||||
C->>ESS: createScript(request)
|
||||
ESS->>ESS: assembleInput(request)
|
||||
ESS->>ACS: callWorkflowByConfigKey(configKey, input, userId)
|
||||
ACS->>AICS: getByConfigKey(configKey)
|
||||
AICS->>DB: SELECT * FROM t_ai_config WHERE config_key = ?
|
||||
DB-->>AICS: AiConfig
|
||||
AICS-->>ACS: AiConfig
|
||||
ACS->>ACS: buildWorkflowRequest(config, input, userId)
|
||||
ACS->>COZE: POST /v1/workflow/stream_run
|
||||
COZE-->>ACS: SSE Stream Response
|
||||
ACS->>ACS: parseStreamResponse(response)
|
||||
ACS-->>ESS: AI Generated Content
|
||||
ESS->>ESS: parseAndSaveScript(content)
|
||||
ESS->>DB: INSERT INTO t_epic_script
|
||||
ESS-->>C: EpicScriptResponse
|
||||
```
|
||||
|
||||
## Components and Interfaces
|
||||
|
||||
### 1. AiChatService 接口扩展
|
||||
|
||||
```java
|
||||
/**
|
||||
* AI聊天服务接口 - 新增通用工作流调用方法
|
||||
*/
|
||||
public interface AiChatService {
|
||||
|
||||
// ... 现有方法 ...
|
||||
|
||||
/**
|
||||
* 通过配置键调用Coze工作流API
|
||||
*
|
||||
* @param configKey AI配置键(如:coze.course.life.generate)
|
||||
* @param input 输入参数,将作为parameters.input传递给工作流
|
||||
* @param userId 用户ID
|
||||
* @return AI生成的内容
|
||||
*/
|
||||
String callWorkflowByConfigKey(String configKey, String input, String userId);
|
||||
|
||||
/**
|
||||
* 通过配置键调用Coze工作流API(带自定义参数)
|
||||
*
|
||||
* @param configKey AI配置键
|
||||
* @param parameters 自定义参数Map,将合并到请求的parameters中
|
||||
* @param userId 用户ID
|
||||
* @return AI生成的内容
|
||||
*/
|
||||
String callWorkflowByConfigKey(String configKey, Map<String, Object> parameters, String userId);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. AiConfigService 接口扩展
|
||||
|
||||
```java
|
||||
/**
|
||||
* AI配置服务接口 - 新增按配置键获取方法
|
||||
*/
|
||||
public interface AiConfigService {
|
||||
|
||||
// ... 现有方法 ...
|
||||
|
||||
/**
|
||||
* 根据配置键获取AI配置
|
||||
*
|
||||
* @param configKey 配置键
|
||||
* @return AI配置,如果不存在或已禁用则返回null
|
||||
*/
|
||||
AiConfig getByConfigKey(String configKey);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. EpicScriptService 接口(无变化)
|
||||
|
||||
现有接口保持不变,实现层调用新的AI服务方法。
|
||||
|
||||
## Data Models
|
||||
|
||||
### Coze工作流请求格式
|
||||
|
||||
```json
|
||||
{
|
||||
"workflow_id": "7586262962160762926",
|
||||
"user_id": "user_123",
|
||||
"stream": true,
|
||||
"parameters": {
|
||||
"input": "用户填写的信息组装后的字符串",
|
||||
"user_id": "user_123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Coze工作流响应格式(SSE)
|
||||
|
||||
```
|
||||
id: 0
|
||||
event: Message
|
||||
data: {"node_title":"End","node_execute_uuid":"","usage":{"token_count":1571,"output_count":812,"input_count":759},"node_is_finish":true,"node_seq_id":"0","content":"{\"output\":\"AI生成的内容...\"}","content_type":"text","node_type":"End","node_id":"900001"}
|
||||
|
||||
id: 1
|
||||
event: Done
|
||||
data: {"node_execute_uuid":"","debug_url":"..."}
|
||||
```
|
||||
|
||||
### 用户输入组装格式
|
||||
|
||||
```
|
||||
剧本标题:{title}
|
||||
主题/渴望:{theme}
|
||||
风格:{style}
|
||||
篇幅:{length}
|
||||
序幕(低谷回响):{plotIntro}
|
||||
转折(契机出现):{plotTurning}
|
||||
高潮(命运抉择):{plotClimax}
|
||||
结局(新的开始):{plotEnding}
|
||||
```
|
||||
|
||||
## Correctness Properties
|
||||
|
||||
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
|
||||
|
||||
### Property 1: Request Format Correctness (请求格式正确性)
|
||||
|
||||
*For any* valid AiConfig and input parameters, the generated Coze workflow request SHALL contain:
|
||||
- workflow_id from the AiConfig
|
||||
- user_id from the call parameters
|
||||
- stream set to true
|
||||
- parameters.input containing the input string
|
||||
- Authorization header with "Bearer {api_token}"
|
||||
- Content-Type header set to "application/json"
|
||||
|
||||
**Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.5, 2.6**
|
||||
|
||||
### Property 2: Stream Response Parsing (流式响应解析)
|
||||
|
||||
*For any* valid Coze SSE stream response containing an "event: Message" line followed by a "data:" line with JSON containing "node_type": "End" and a "content" field with nested JSON containing "output", the parser SHALL extract and return the output value.
|
||||
|
||||
**Validates: Requirements 3.1, 3.2, 3.3**
|
||||
|
||||
### Property 3: Input Assembly Completeness (输入组装完整性)
|
||||
|
||||
*For any* EpicScriptCreateRequest with non-null field values, the assembled input string SHALL contain all provided field values (title, theme, style, length, plotIntro, plotTurning, plotClimax, plotEnding).
|
||||
|
||||
**Validates: Requirements 4.2**
|
||||
|
||||
### Property 4: Configuration Application (配置应用正确性)
|
||||
|
||||
*For any* AiConfig retrieved by config_key:
|
||||
- If is_enabled = 0, the system SHALL reject the config and throw an exception
|
||||
- The api_base_url, api_token, and workflow_id SHALL be used in the request construction
|
||||
- The custom_params SHALL be merged with runtime parameters
|
||||
|
||||
**Validates: Requirements 1.3, 5.2, 5.3**
|
||||
|
||||
### Property 5: Error Message Quality (错误消息质量)
|
||||
|
||||
*For any* error that occurs during AI API calls:
|
||||
- The error message SHALL be meaningful and descriptive
|
||||
- The error message SHALL NOT contain sensitive information such as API tokens
|
||||
- The error message SHALL include relevant context (config_key, status code if applicable)
|
||||
|
||||
**Validates: Requirements 6.4, 6.5**
|
||||
|
||||
## Error Handling
|
||||
|
||||
### 错误类型和处理策略
|
||||
|
||||
| 错误类型 | 处理策略 | 返回值 |
|
||||
|---------|---------|--------|
|
||||
| 配置不存在 | 抛出RuntimeException | "未找到AI配置: {configKey}" |
|
||||
| 配置已禁用 | 抛出RuntimeException | "AI配置已禁用: {configKey}" |
|
||||
| API调用超时 | 重试(根据配置) | 重试失败后返回错误消息 |
|
||||
| HTTP非200响应 | 记录日志,返回错误 | "AI服务调用失败: {statusCode}" |
|
||||
| 流式解析失败 | 记录原始数据,返回错误 | "AI响应解析失败" |
|
||||
| JSON解析失败 | 返回原始内容 | 原始content字符串 |
|
||||
|
||||
### 日志记录规范
|
||||
|
||||
```java
|
||||
// 请求日志
|
||||
log.info("调用Coze工作流: configKey={}, workflowId={}, userId={}", configKey, workflowId, userId);
|
||||
|
||||
// 响应日志
|
||||
log.info("Coze工作流响应: configKey={}, contentLength={}", configKey, content.length());
|
||||
|
||||
// 错误日志
|
||||
log.error("Coze工作流调用失败: configKey={}, statusCode={}, error={}", configKey, statusCode, errorMsg);
|
||||
```
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### 单元测试
|
||||
|
||||
1. **AiConfigService测试**
|
||||
- 测试getByConfigKey返回正确配置
|
||||
- 测试配置不存在时返回null
|
||||
- 测试配置禁用时返回null
|
||||
|
||||
2. **请求构建测试**
|
||||
- 测试buildWorkflowRequest生成正确的请求格式
|
||||
- 测试参数合并逻辑
|
||||
|
||||
3. **响应解析测试**
|
||||
- 测试parseStreamResponse正确解析SSE格式
|
||||
- 测试extractOutputFromContent正确提取output字段
|
||||
|
||||
4. **输入组装测试**
|
||||
- 测试assembleInput正确组装用户输入
|
||||
|
||||
### 属性测试
|
||||
|
||||
使用JUnit 5进行属性测试,每个属性测试至少运行100次迭代:
|
||||
|
||||
1. **Property 1: Request Format Correctness**
|
||||
- 生成随机的AiConfig和输入参数
|
||||
- 验证生成的请求包含所有必需字段
|
||||
- 验证请求头正确设置
|
||||
- **Feature: coze-ai-integration, Property 1: Request Format Correctness**
|
||||
|
||||
2. **Property 2: Stream Response Parsing**
|
||||
- 生成各种有效的SSE格式响应
|
||||
- 验证正确提取output内容
|
||||
- 测试边界情况(空content、嵌套JSON等)
|
||||
- **Feature: coze-ai-integration, Property 2: Stream Response Parsing**
|
||||
|
||||
3. **Property 3: Input Assembly Completeness**
|
||||
- 生成随机的EpicScriptCreateRequest
|
||||
- 验证所有非空字段都出现在组装结果中
|
||||
- **Feature: coze-ai-integration, Property 3: Input Assembly Completeness**
|
||||
|
||||
4. **Property 4: Configuration Application**
|
||||
- 生成随机的AiConfig
|
||||
- 验证配置值正确应用到请求
|
||||
- 验证禁用配置被拒绝
|
||||
- **Feature: coze-ai-integration, Property 4: Configuration Application**
|
||||
|
||||
5. **Property 5: Error Message Quality**
|
||||
- 模拟各种错误场景
|
||||
- 验证错误消息有意义且不包含敏感信息
|
||||
- **Feature: coze-ai-integration, Property 5: Error Message Quality**
|
||||
|
||||
### 集成测试
|
||||
|
||||
1. 端到端测试:从Controller到Coze API的完整调用流程
|
||||
2. 配置变更测试:验证配置更新后立即生效
|
||||
@@ -0,0 +1,91 @@
|
||||
# Requirements Document
|
||||
|
||||
## Introduction
|
||||
|
||||
本文档定义了优化爽文剧本创建接口(EpicScriptServiceImpl#createScript)的需求,通过调用Coze AI API来生成剧本内容。同时重构AiChatServiceImpl中的AI调用封装,使其成为通用的AI接口调用服务,支持根据配置信息调用不同的AI接口。
|
||||
|
||||
## Glossary
|
||||
|
||||
- **Coze_API**: 扣子AI平台提供的工作流流式调用接口
|
||||
- **AiConfig**: AI配置实体,存储在t_ai_config表中,包含API地址、Token、工作流ID等配置信息
|
||||
- **config_key**: AI配置的唯一标识键,用于获取特定场景的配置
|
||||
- **workflow_id**: Coze工作流ID,用于指定调用哪个AI工作流
|
||||
- **Stream_Response**: 流式响应,Coze API以SSE(Server-Sent Events)格式返回数据
|
||||
- **EpicScript**: 爽文剧本实体,存储用户创建的剧本信息
|
||||
- **input_parameter**: 传递给Coze工作流的输入参数,包含用户填写的信息
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement 1: 通用AI接口调用服务
|
||||
|
||||
**User Story:** As a developer, I want to have a generic AI API calling service, so that I can easily call different AI configurations without duplicating code.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE AiChatService SHALL provide a generic method to call Coze workflow API by config_key
|
||||
2. WHEN a config_key is provided, THE AiChatService SHALL retrieve the corresponding AiConfig from database
|
||||
3. WHEN the AiConfig is retrieved, THE AiChatService SHALL construct the request using api_base_url, api_token, and workflow_id from the config
|
||||
4. THE AiChatService SHALL support passing custom input parameters to the workflow
|
||||
5. THE AiChatService SHALL handle stream response by default and extract the output content from the response
|
||||
6. IF the AiConfig is not found or disabled, THEN THE AiChatService SHALL throw an appropriate exception with clear error message
|
||||
|
||||
### Requirement 2: Coze工作流请求构建
|
||||
|
||||
**User Story:** As a developer, I want the system to correctly build Coze workflow requests, so that the AI can process my input and return expected results.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN building a Coze workflow request, THE System SHALL include workflow_id from AiConfig
|
||||
2. WHEN building a Coze workflow request, THE System SHALL include user_id parameter
|
||||
3. WHEN building a Coze workflow request, THE System SHALL set stream to true for streaming response
|
||||
4. WHEN building a Coze workflow request, THE System SHALL include the input parameter in the parameters object
|
||||
5. THE System SHALL set Authorization header with Bearer token from AiConfig.api_token
|
||||
6. THE System SHALL set Content-Type header to application/json
|
||||
|
||||
### Requirement 3: 流式响应解析
|
||||
|
||||
**User Story:** As a developer, I want the system to correctly parse Coze streaming responses, so that I can get the AI-generated content.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN receiving a stream response, THE System SHALL parse SSE format data (event: and data: lines)
|
||||
2. WHEN the event is "Message" and node_type is "End", THE System SHALL extract the content field
|
||||
3. WHEN the content contains JSON with output field, THE System SHALL extract the output value as the final result
|
||||
4. WHEN the event is "Done", THE System SHALL complete the stream processing
|
||||
5. IF parsing fails, THEN THE System SHALL log the error and return an appropriate error message
|
||||
|
||||
### Requirement 4: 爽文剧本AI生成
|
||||
|
||||
**User Story:** As a user, I want to create epic scripts using AI, so that I can get professionally generated story content based on my input.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. WHEN creating an epic script, THE EpicScriptService SHALL call Coze AI using config_key "coze.course.life.generate"
|
||||
2. THE EpicScriptService SHALL assemble user input (title, theme, style, length, plotIntro, plotTurning, plotClimax, plotEnding) into a formatted input string
|
||||
3. WHEN the AI returns the generated content, THE EpicScriptService SHALL parse and store the result in the EpicScript entity
|
||||
4. THE EpicScriptService SHALL store the AI-generated content in appropriate fields (plotJson or dedicated content field)
|
||||
5. IF the AI call fails, THEN THE EpicScriptService SHALL log the error and return null or throw an exception
|
||||
|
||||
### Requirement 5: 配置管理
|
||||
|
||||
**User Story:** As an administrator, I want to manage AI configurations in the database, so that I can easily update API settings without code changes.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. THE System SHALL retrieve AiConfig by config_key using AiConfigService
|
||||
2. THE System SHALL validate that the AiConfig is enabled (is_enabled = 1) before use
|
||||
3. THE System SHALL use custom_params from AiConfig to merge with runtime parameters
|
||||
4. THE System SHALL respect timeout_ms setting from AiConfig for API calls
|
||||
5. THE System SHALL support retry logic based on retry_count and retry_delay_ms from AiConfig
|
||||
|
||||
### Requirement 6: 错误处理
|
||||
|
||||
**User Story:** As a developer, I want proper error handling for AI API calls, so that I can diagnose and fix issues quickly.
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. IF the API returns non-200 status code, THEN THE System SHALL log the error with status code and response body
|
||||
2. IF the stream parsing fails, THEN THE System SHALL log the raw stream data for debugging
|
||||
3. IF the network request times out, THEN THE System SHALL retry based on configuration
|
||||
4. THE System SHALL provide meaningful error messages to the caller
|
||||
5. THE System SHALL not expose sensitive information (like API tokens) in error messages
|
||||
@@ -0,0 +1,107 @@
|
||||
# Implementation Plan: Coze AI Integration
|
||||
|
||||
## Overview
|
||||
|
||||
本实现计划将重构AiChatServiceImpl,添加通用的Coze工作流调用方法,并优化EpicScriptServiceImpl#createScript接口以调用Coze AI生成剧本内容。实现采用增量方式,每个任务都建立在前一个任务的基础上。
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] 1. 扩展AiConfigService接口和实现
|
||||
- [x] 1.1 在AiConfigService接口中添加getByConfigKey方法
|
||||
- 添加方法签名:`AiConfig getByConfigKey(String configKey)`
|
||||
- 添加方法级注释说明功能和参数
|
||||
- _Requirements: 5.1_
|
||||
- [x] 1.2 在AiConfigServiceImpl中实现getByConfigKey方法
|
||||
- 使用LambdaQueryWrapper查询config_key匹配且is_enabled=1的配置
|
||||
- 返回查询结果,不存在则返回null
|
||||
- _Requirements: 1.2, 5.1, 5.2_
|
||||
|
||||
- [x] 2. 扩展AiChatService接口
|
||||
- [x] 2.1 在AiChatService接口中添加callWorkflowByConfigKey方法
|
||||
- 添加方法签名:`String callWorkflowByConfigKey(String configKey, String input, String userId)`
|
||||
- 添加重载方法:`String callWorkflowByConfigKey(String configKey, Map<String, Object> parameters, String userId)`
|
||||
- 添加方法级注释说明功能、参数和返回值
|
||||
- _Requirements: 1.1, 1.4_
|
||||
|
||||
- [x] 3. 实现通用工作流调用方法
|
||||
- [x] 3.1 在AiChatServiceImpl中实现callWorkflowByConfigKey方法
|
||||
- 调用aiConfigService.getByConfigKey获取配置
|
||||
- 验证配置存在且启用,否则抛出异常
|
||||
- 构建工作流请求(workflow_id, user_id, stream=true, parameters.input)
|
||||
- 设置请求头(Authorization, Content-Type)
|
||||
- _Requirements: 1.2, 1.3, 1.6, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6_
|
||||
- [x] 3.2 实现流式响应处理方法
|
||||
- 解析SSE格式响应(event:和data:行)
|
||||
- 提取event为Message且node_type为End的content
|
||||
- 从content的JSON中提取output字段
|
||||
- 处理Done事件完成流处理
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4_
|
||||
- [x] 3.3 实现错误处理逻辑
|
||||
- 处理配置不存在/禁用的情况
|
||||
- 处理API调用失败(非200状态码)
|
||||
- 处理流式解析失败
|
||||
- 确保错误消息不包含敏感信息
|
||||
- _Requirements: 1.6, 3.5, 6.1, 6.2, 6.4, 6.5_
|
||||
- [x] 3.4 编写Property 1属性测试:请求格式正确性
|
||||
- **Property 1: Request Format Correctness**
|
||||
- **Validates: Requirements 2.1, 2.2, 2.3, 2.4, 2.5, 2.6**
|
||||
- [x] 3.5 编写Property 2属性测试:流式响应解析
|
||||
- **Property 2: Stream Response Parsing**
|
||||
- **Validates: Requirements 3.1, 3.2, 3.3**
|
||||
|
||||
- [x] 4. Checkpoint - 验证通用AI调用服务
|
||||
- 确保所有测试通过,如有问题请询问用户
|
||||
|
||||
- [x] 5. 实现爽文剧本AI生成
|
||||
- [x] 5.1 在EpicScriptServiceImpl中添加输入组装方法
|
||||
- 创建assembleScriptInput方法
|
||||
- 将EpicScriptCreateRequest的字段组装为格式化字符串
|
||||
- 包含title, theme, style, length, plotIntro, plotTurning, plotClimax, plotEnding
|
||||
- _Requirements: 4.2_
|
||||
- [x] 5.2 修改createScript方法调用AI生成
|
||||
- 调用assembleScriptInput组装输入
|
||||
- 调用aiChatService.callWorkflowByConfigKey("coze.course.life.generate", input, userId)
|
||||
- 解析AI返回的内容并存储到EpicScript实体
|
||||
- 处理AI调用失败的情况
|
||||
- _Requirements: 4.1, 4.3, 4.4, 4.5_
|
||||
- [x] 5.3 编写Property 3属性测试:输入组装完整性
|
||||
- **Property 3: Input Assembly Completeness**
|
||||
- **Validates: Requirements 4.2**
|
||||
|
||||
- [x] 6. 实现配置参数合并
|
||||
- [x] 6.1 实现custom_params合并逻辑
|
||||
- 解析AiConfig.customParams JSON字符串
|
||||
- 将custom_params与运行时参数合并
|
||||
- 运行时参数优先级高于custom_params
|
||||
- _Requirements: 5.3_
|
||||
- [x] 6.2 实现超时和重试配置
|
||||
- 应用AiConfig.timeoutMs设置
|
||||
- 实现基于retry_count和retry_delay_ms的重试逻辑
|
||||
- _Requirements: 5.4, 5.5, 6.3_
|
||||
- [x] 6.3 编写Property 4属性测试:配置应用正确性
|
||||
- **Property 4: Configuration Application**
|
||||
- **Validates: Requirements 1.3, 5.2, 5.3**
|
||||
|
||||
- [x] 7. 完善错误处理和日志
|
||||
- [x] 7.1 完善错误消息格式
|
||||
- 确保错误消息包含config_key和状态码
|
||||
- 确保不暴露API token等敏感信息
|
||||
- 添加详细的日志记录
|
||||
- _Requirements: 6.1, 6.2, 6.4, 6.5_
|
||||
- [x] 7.2 编写Property 5属性测试:错误消息质量
|
||||
- **Property 5: Error Message Quality**
|
||||
- **Validates: Requirements 6.4, 6.5**
|
||||
|
||||
- [x] 8. Final Checkpoint - 确保所有测试通过
|
||||
- 运行所有单元测试和属性测试
|
||||
- 确保所有测试通过,如有问题请询问用户
|
||||
|
||||
## Notes
|
||||
|
||||
- All tasks are required for comprehensive implementation
|
||||
- Each task references specific requirements for traceability
|
||||
- Checkpoints ensure incremental validation
|
||||
- Property tests validate universal correctness properties
|
||||
- Unit tests validate specific examples and edge cases
|
||||
- 实现语言:Java (Spring Boot)
|
||||
- 测试框架:JUnit 5
|
||||
Reference in New Issue
Block a user