test(cache): 修复CacheConfigTest边界值测试
- 修改 shouldVerifyCacheManager_withMaximumIntegerTtl 为 shouldVerifyCacheManager_withMaximumAllowedTtl - 使用正确的最大TTL值(10080分钟,7天)而不是 Integer.MAX_VALUE - 新增 shouldThrowException_whenTtlExceedsMaximum 测试验证边界检查 - 所有1266个测试用例通过 - 覆盖率: 指令81.89%, 行88.48%, 分支51.55% docs: 添加项目状态报告 - 生成 PROJECT_STATUS_REPORT.md 详细记录项目当前状态 - 包含质量指标、已完成功能、待办事项和技术债务
This commit is contained in:
562
src/test/java/com/mosquito/project/dto/UseApiKeyRequestTest.java
Normal file
562
src/test/java/com/mosquito/project/dto/UseApiKeyRequestTest.java
Normal file
@@ -0,0 +1,562 @@
|
||||
package com.mosquito.project.dto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.Validation;
|
||||
import jakarta.validation.Validator;
|
||||
import jakarta.validation.ValidatorFactory;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.NullAndEmptySource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* UseApiKeyRequest DTO测试
|
||||
*/
|
||||
@DisplayName("UseApiKeyRequest DTO测试")
|
||||
class UseApiKeyRequestTest {
|
||||
|
||||
private Validator validator;
|
||||
private UseApiKeyRequest request;
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
validator = factory.getValidator();
|
||||
request = new UseApiKeyRequest();
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("验证测试")
|
||||
class ValidationTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("有效的API密钥应该通过验证")
|
||||
void shouldPassValidation_WhenValidApiKey() {
|
||||
// Given
|
||||
request.setApiKey("valid-api-key-123");
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", "\t", "\n", "\r"})
|
||||
@DisplayName("无效API密钥应该失败验证")
|
||||
void shouldFailValidation_WhenInvalidApiKey(String apiKey) {
|
||||
// Given
|
||||
request.setApiKey(apiKey);
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isNotEmpty();
|
||||
assertThat(violations).hasSize(1);
|
||||
|
||||
ConstraintViolation<UseApiKeyRequest> violation = violations.iterator().next();
|
||||
assertThat(violation.getPropertyPath().toString()).isEqualTo("apiKey");
|
||||
assertThat(violation.getMessage()).isEqualTo("API密钥不能为空");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("包含空格的API密钥应该通过验证")
|
||||
void shouldPassValidation_WhenApiKeyContainsWhitespace() {
|
||||
// Given
|
||||
request.setApiKey("key with spaces");
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("特殊字符API密钥应该通过验证")
|
||||
void shouldPassValidation_WhenApiKeyContainsSpecialChars() {
|
||||
// Given
|
||||
request.setApiKey("key-!@#$%^&*()_+");
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("长API密钥应该通过验证")
|
||||
void shouldPassValidation_WhenApiKeyIsLong() {
|
||||
// Given
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
sb.append("k");
|
||||
}
|
||||
request.setApiKey(sb.toString());
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Unicode字符API密钥应该通过验证")
|
||||
void shouldPassValidation_WhenApiKeyContainsUnicode() {
|
||||
// Given
|
||||
request.setApiKey("密钥-中文-🔑");
|
||||
|
||||
// When
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(request);
|
||||
|
||||
// Then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Getter和Setter测试")
|
||||
class GetterSetterTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("apiKey字段的getter和setter应该正常工作")
|
||||
void shouldWorkCorrectly_ApiKeyGetterSetter() {
|
||||
// Given
|
||||
String apiKey = "test-api-key";
|
||||
|
||||
// When
|
||||
request.setApiKey(apiKey);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("多次设置apiKey应该正确更新")
|
||||
void shouldUpdateCorrectly_WhenSettingApiKeyMultipleTimes() {
|
||||
// Given
|
||||
request.setApiKey("key-1");
|
||||
assertThat(request.getApiKey()).isEqualTo("key-1");
|
||||
|
||||
// When
|
||||
request.setApiKey("key-2");
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo("key-2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("设置null值应该正确处理")
|
||||
void shouldHandleNullValues_WhenSettingFields() {
|
||||
// Given
|
||||
request.setApiKey("test-key");
|
||||
assertThat(request.getApiKey()).isNotNull();
|
||||
|
||||
// When
|
||||
request.setApiKey(null);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("设置空字符串应该正确处理")
|
||||
void shouldHandleEmptyString_WhenSettingFields() {
|
||||
// Given
|
||||
request.setApiKey("test-key");
|
||||
|
||||
// When
|
||||
request.setApiKey("");
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("边界值测试")
|
||||
class BoundaryTests {
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"a", // 单字符
|
||||
"AB", // 双字符
|
||||
"0123456789", // 数字
|
||||
"key-with-dashes", // 带横线
|
||||
"key_with_underscores", // 带下划线
|
||||
"key.with.dots", // 带点
|
||||
"key:with:colons", // 带冒号
|
||||
"key/with/slashes", // 带斜杠
|
||||
"key+with+plus", // 带加号
|
||||
"key=with=equals", // 带等号
|
||||
"key?with?question", // 带问号
|
||||
"key&with&ersand", // 带&
|
||||
})
|
||||
@DisplayName("各种格式API密钥应该正确处理")
|
||||
void shouldHandleVariousFormats(String apiKey) {
|
||||
// When
|
||||
request.setApiKey(apiKey);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Unicode字符API密钥应该正确处理")
|
||||
void shouldHandleUnicodeCharacters() {
|
||||
// Given
|
||||
String[] unicodeKeys = {
|
||||
"密钥-中文测试",
|
||||
"ключ-русский",
|
||||
"キー-日本語",
|
||||
"🔑-emoji-test",
|
||||
"مفتاح-عربي",
|
||||
"🔐🔑🛡️-多emoji"
|
||||
};
|
||||
|
||||
for (String key : unicodeKeys) {
|
||||
// When
|
||||
request.setApiKey(key);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("极大长度API密钥应该正确处理")
|
||||
void shouldHandleExtremelyLongKey() {
|
||||
// Given
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
sb.append("A");
|
||||
}
|
||||
String extremelyLongKey = sb.toString();
|
||||
|
||||
// When
|
||||
request.setApiKey(extremelyLongKey);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).hasSize(10000);
|
||||
assertThat(request.getApiKey()).isEqualTo(extremelyLongKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JSON特殊字符API密钥应该正确处理")
|
||||
void shouldHandleJsonSpecialCharacters() {
|
||||
// Given
|
||||
String jsonSpecialKey = "key{with}[brackets]\"quotes\"'apostrophe'";
|
||||
|
||||
// When
|
||||
request.setApiKey(jsonSpecialKey);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(jsonSpecialKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("包含换行符API密钥应该正确处理")
|
||||
void shouldHandleNewlines() {
|
||||
// Given
|
||||
String keyWithNewlines = "line1\nline2\r\nline3\t";
|
||||
|
||||
// When
|
||||
request.setApiKey(keyWithNewlines);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(keyWithNewlines);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空白字符组合API密钥应该正确处理")
|
||||
void shouldHandleWhitespaceCombinations() {
|
||||
// Given
|
||||
String[] whitespaceKeys = {
|
||||
"key with spaces",
|
||||
"key\twith\ttabs",
|
||||
" leading-spaces",
|
||||
"trailing-spaces ",
|
||||
" both-spaces "
|
||||
};
|
||||
|
||||
for (String key : whitespaceKeys) {
|
||||
// When
|
||||
request.setApiKey(key);
|
||||
|
||||
// Then
|
||||
assertThat(request.getApiKey()).isEqualTo(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("JSON序列化测试")
|
||||
class JsonSerializationTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("完整对象应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
|
||||
// Given
|
||||
request.setApiKey("test-api-key-123");
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(request);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("\"apiKey\":\"test-api-key-123\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("null值应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithNullValue() throws JsonProcessingException {
|
||||
// Given
|
||||
request.setApiKey(null);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(request);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("\"apiKey\":null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空字符串应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithEmptyString() throws JsonProcessingException {
|
||||
// Given
|
||||
request.setApiKey("");
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(request);
|
||||
|
||||
// Then
|
||||
assertThat(json).contains("\"apiKey\":\"\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("特殊字符应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
|
||||
// Given
|
||||
request.setApiKey("key-🔑-测试");
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(request);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
// 验证反序列化后值相同
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
assertThat(deserialized.getApiKey()).isEqualTo("key-🔑-测试");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JSON转义字符应该正确序列化")
|
||||
void shouldSerializeCorrectly_WithJsonEscapes() throws JsonProcessingException {
|
||||
// Given
|
||||
String keyWithEscapes = "line1\nline2\t\"quoted\"";
|
||||
request.setApiKey(keyWithEscapes);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(request);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
// 验证反序列化后值相同
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
assertThat(deserialized.getApiKey()).isEqualTo(keyWithEscapes);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("JSON反序列化测试")
|
||||
class JsonDeserializationTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("完整JSON应该正确反序列化")
|
||||
void shouldDeserializeCorrectly_CompleteJson() throws JsonProcessingException {
|
||||
// Given
|
||||
String json = "{\"apiKey\":\"test-api-key-12345\"}";
|
||||
|
||||
// When
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
|
||||
// Then
|
||||
assertThat(deserialized.getApiKey()).isEqualTo("test-api-key-12345");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("null值JSON应该正确反序列化")
|
||||
void shouldDeserializeCorrectly_WithNullValue() throws JsonProcessingException {
|
||||
// Given
|
||||
String json = "{\"apiKey\":null}";
|
||||
|
||||
// When
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
|
||||
// Then
|
||||
assertThat(deserialized.getApiKey()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空字符串JSON应该正确反序列化")
|
||||
void shouldDeserializeCorrectly_WithEmptyString() throws JsonProcessingException {
|
||||
// Given
|
||||
String json = "{\"apiKey\":\"\"}";
|
||||
|
||||
// When
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
|
||||
// Then
|
||||
assertThat(deserialized.getApiKey()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空对象JSON应该正确反序列化")
|
||||
void shouldDeserializeCorrectly_EmptyObjectJson() throws JsonProcessingException {
|
||||
// Given
|
||||
String json = "{}";
|
||||
|
||||
// When
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
|
||||
// Then
|
||||
assertThat(deserialized.getApiKey()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("特殊字符JSON应该正确反序列化")
|
||||
void shouldDeserializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
|
||||
// Given
|
||||
String json = "{\"apiKey\":\"key-🔑-测试\"}";
|
||||
|
||||
// When
|
||||
UseApiKeyRequest deserialized = objectMapper.readValue(json, UseApiKeyRequest.class);
|
||||
|
||||
// Then
|
||||
assertThat(deserialized.getApiKey()).isEqualTo("key-🔑-测试");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JSON格式错误应该抛出异常")
|
||||
void shouldThrowException_WhenJsonIsMalformed() {
|
||||
// Given
|
||||
String malformedJson = "{\"apiKey\":\"test\""; // 缺少闭合括号
|
||||
|
||||
// When & Then
|
||||
assertThatThrownBy(() -> objectMapper.readValue(malformedJson, UseApiKeyRequest.class))
|
||||
.isInstanceOf(JsonProcessingException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("对象行为测试")
|
||||
class ObjectBehaviorTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("两个相同apiKey的请求应该相等")
|
||||
void shouldBeEqual_WhenSameApiKey() {
|
||||
// Given
|
||||
UseApiKeyRequest request1 = new UseApiKeyRequest();
|
||||
UseApiKeyRequest request2 = new UseApiKeyRequest();
|
||||
request1.setApiKey("same-key");
|
||||
request2.setApiKey("same-key");
|
||||
|
||||
// Then
|
||||
assertThat(request1.getApiKey()).isEqualTo(request2.getApiKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("两个不同apiKey的请求应该不相等")
|
||||
void shouldNotBeEqual_WhenDifferentApiKey() {
|
||||
// Given
|
||||
UseApiKeyRequest request1 = new UseApiKeyRequest();
|
||||
UseApiKeyRequest request2 = new UseApiKeyRequest();
|
||||
request1.setApiKey("key-1");
|
||||
request2.setApiKey("key-2");
|
||||
|
||||
// Then
|
||||
assertThat(request1.getApiKey()).isNotEqualTo(request2.getApiKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("多次调用getter应该返回相同值")
|
||||
void shouldReturnSameValue_WhenCallingGetterMultipleTimes() {
|
||||
// Given
|
||||
request.setApiKey("consistent-key");
|
||||
|
||||
// When & Then
|
||||
assertThat(request.getApiKey()).isEqualTo("consistent-key");
|
||||
assertThat(request.getApiKey()).isEqualTo("consistent-key");
|
||||
assertThat(request.getApiKey()).isEqualTo("consistent-key");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("并发安全测试")
|
||||
class ConcurrencyTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("多线程并发操作应该是安全的")
|
||||
void shouldBeThreadSafe_ConcurrentOperations() throws InterruptedException {
|
||||
// Given
|
||||
int threadCount = 10;
|
||||
Thread[] threads = new Thread[threadCount];
|
||||
boolean[] results = new boolean[threadCount];
|
||||
|
||||
// When
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
final int threadIndex = i;
|
||||
threads[i] = new Thread(() -> {
|
||||
try {
|
||||
UseApiKeyRequest localRequest = new UseApiKeyRequest();
|
||||
localRequest.setApiKey("key-" + threadIndex);
|
||||
|
||||
// 验证getter
|
||||
assertThat(localRequest.getApiKey()).isEqualTo("key-" + threadIndex);
|
||||
|
||||
// 验证验证器
|
||||
Set<ConstraintViolation<UseApiKeyRequest>> violations = validator.validate(localRequest);
|
||||
assertThat(violations).isEmpty();
|
||||
|
||||
results[threadIndex] = true;
|
||||
} catch (Exception e) {
|
||||
results[threadIndex] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 启动所有线程
|
||||
for (Thread thread : threads) {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
// 等待所有线程完成
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
// Then
|
||||
for (int i = 0; i < threadCount; i++) {
|
||||
assertThat(results[i]).isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user