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:
@@ -0,0 +1,426 @@
|
||||
package com.mosquito.project.dto;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
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 static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* CreateApiKeyResponse DTO测试
|
||||
*/
|
||||
@DisplayName("CreateApiKeyResponse DTO测试")
|
||||
class CreateApiKeyResponseTest {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("构造函数测试")
|
||||
class ConstructorTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("全参数构造函数应该正确设置apiKey字段")
|
||||
void shouldSetApiKeyCorrectly_WhenUsingAllArgsConstructor() {
|
||||
// Given
|
||||
String apiKey = "test-api-key-12345";
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("null值构造函数应该正确处理")
|
||||
void shouldHandleNull_WhenUsingConstructor() {
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(null);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空字符串构造函数应该正确处理")
|
||||
void shouldHandleEmptyString_WhenUsingConstructor() {
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse("");
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空白字符串构造函数应该正确处理")
|
||||
void shouldHandleWhitespace_WhenUsingConstructor() {
|
||||
// Given
|
||||
String whitespaceKey = " ";
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(whitespaceKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(whitespaceKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("长字符串构造函数应该正确处理")
|
||||
void shouldHandleLongString_WhenUsingConstructor() {
|
||||
// Given
|
||||
StringBuilder longKey = new StringBuilder();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
longKey.append("key").append(i);
|
||||
}
|
||||
String longApiKey = longKey.toString();
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(longApiKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(longApiKey);
|
||||
assertThat(response.getApiKey()).hasSizeGreaterThan(2000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("特殊字符apiKey构造函数应该正确处理")
|
||||
void shouldHandleSpecialCharacters_WhenUsingConstructor() {
|
||||
// Given
|
||||
String specialKey = "key-🔑-测试!@#$%^&*()_+-=[]{}|;':\",./<>?";
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(specialKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("包含换行符apiKey构造函数应该正确处理")
|
||||
void shouldHandleNewlines_WhenUsingConstructor() {
|
||||
// Given
|
||||
String keyWithNewlines = "line1\nline2\r\nline3\t";
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithNewlines);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(keyWithNewlines);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("Getter测试")
|
||||
class GetterTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("getApiKey应该返回正确的值")
|
||||
void shouldReturnCorrectValue_WhenUsingGetter() {
|
||||
// Given
|
||||
String apiKey = "my-secret-api-key";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// When
|
||||
String result = response.getApiKey();
|
||||
|
||||
// Then
|
||||
assertThat(result).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("getApiKey应该返回null当值为null")
|
||||
void shouldReturnNull_WhenValueIsNull() {
|
||||
// Given
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(null);
|
||||
|
||||
// When
|
||||
String result = response.getApiKey();
|
||||
|
||||
// Then
|
||||
assertThat(result).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("getApiKey应该返回空字符串当值为空")
|
||||
void shouldReturnEmptyString_WhenValueIsEmpty() {
|
||||
// Given
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse("");
|
||||
|
||||
// When
|
||||
String result = response.getApiKey();
|
||||
|
||||
// Then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("边界值测试")
|
||||
class BoundaryTests {
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@ValueSource(strings = {" ", "\t", "\n", "\r"})
|
||||
@DisplayName("边界值apiKey应该正确处理")
|
||||
void shouldHandleBoundaryValues(String apiKey) {
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"a", // 单字符
|
||||
"AB", // 双字符
|
||||
"0123456789", // 数字
|
||||
"abcdefghijklmnopqrstuvwxyz", // 小写字母
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ", // 大写字母
|
||||
"key-with-dashes", // 带横线
|
||||
"key_with_underscores", // 带下划线
|
||||
"key.with.dots", // 带点
|
||||
"key:with:colons", // 带冒号
|
||||
"key/with/slashes" // 带斜杠
|
||||
})
|
||||
@DisplayName("各种格式apiKey应该正确处理")
|
||||
void shouldHandleVariousFormats(String apiKey) {
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Unicode字符apiKey应该正确处理")
|
||||
void shouldHandleUnicodeCharacters() {
|
||||
// Given
|
||||
String[] unicodeKeys = {
|
||||
"密钥-中文测试",
|
||||
"ключ-русский",
|
||||
"キー-日本語",
|
||||
"🔑-emoji-test",
|
||||
"مفتاح-عربي"
|
||||
};
|
||||
|
||||
for (String key : unicodeKeys) {
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(key);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("极大长度apiKey应该正确处理")
|
||||
void shouldHandleExtremelyLongKey() {
|
||||
// Given
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
sb.append("A");
|
||||
}
|
||||
String extremelyLongKey = sb.toString();
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(extremelyLongKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).hasSize(10000);
|
||||
assertThat(response.getApiKey()).isEqualTo(extremelyLongKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JSON特殊字符apiKey应该正确处理")
|
||||
void shouldHandleJsonSpecialCharacters() {
|
||||
// Given
|
||||
String jsonSpecialKey = "key{with}[brackets]\"quotes\"'apostrophe'";
|
||||
|
||||
// When
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(jsonSpecialKey);
|
||||
|
||||
// Then
|
||||
assertThat(response.getApiKey()).isEqualTo(jsonSpecialKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("JSON序列化测试")
|
||||
class JsonSerializationTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("完整对象应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_CompleteObject() throws JsonProcessingException {
|
||||
// Given
|
||||
String apiKey = "test-api-key-12345";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("\"apiKey\":\"test-api-key-12345\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("null值应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithNullValue() throws JsonProcessingException {
|
||||
// Given
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(null);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("\"apiKey\":null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("空字符串应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithEmptyString() throws JsonProcessingException {
|
||||
// Given
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse("");
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
// Then
|
||||
assertThat(json).contains("\"apiKey\":\"\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("特殊字符应该正确序列化为JSON")
|
||||
void shouldSerializeCorrectly_WithSpecialCharacters() throws JsonProcessingException {
|
||||
// Given
|
||||
String specialKey = "key-🔑-测试";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(specialKey);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("apiKey");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JSON转义字符应该正确序列化")
|
||||
void shouldSerializeCorrectly_WithJsonEscapes() throws JsonProcessingException {
|
||||
// Given
|
||||
String keyWithEscapes = "line1\nline2\t\"quoted\"";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(keyWithEscapes);
|
||||
|
||||
// When
|
||||
String json = objectMapper.writeValueAsString(response);
|
||||
|
||||
// Then
|
||||
assertThat(json).isNotNull();
|
||||
assertThat(json).contains("apiKey");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("对象行为测试")
|
||||
class ObjectBehaviorTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("两个相同apiKey的响应应该相等")
|
||||
void shouldBeEqual_WhenSameApiKey() {
|
||||
// Given
|
||||
CreateApiKeyResponse response1 = new CreateApiKeyResponse("same-key");
|
||||
CreateApiKeyResponse response2 = new CreateApiKeyResponse("same-key");
|
||||
|
||||
// Then
|
||||
assertThat(response1.getApiKey()).isEqualTo(response2.getApiKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("两个不同apiKey的响应应该不相等")
|
||||
void shouldNotBeEqual_WhenDifferentApiKey() {
|
||||
// Given
|
||||
CreateApiKeyResponse response1 = new CreateApiKeyResponse("key-1");
|
||||
CreateApiKeyResponse response2 = new CreateApiKeyResponse("key-2");
|
||||
|
||||
// Then
|
||||
assertThat(response1.getApiKey()).isNotEqualTo(response2.getApiKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("多次调用getter应该返回相同值")
|
||||
void shouldReturnSameValue_WhenCallingGetterMultipleTimes() {
|
||||
// Given
|
||||
String apiKey = "consistent-key";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
|
||||
// When & Then
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
assertThat(response.getApiKey()).isEqualTo(apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("并发安全测试")
|
||||
class ConcurrencyTests {
|
||||
|
||||
@Test
|
||||
@DisplayName("多线程并发读取应该是安全的")
|
||||
void shouldBeThreadSafe_ConcurrentReads() throws InterruptedException {
|
||||
// Given
|
||||
String apiKey = "concurrent-key";
|
||||
CreateApiKeyResponse response = new CreateApiKeyResponse(apiKey);
|
||||
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 {
|
||||
for (int j = 0; j < 100; j++) {
|
||||
String value = response.getApiKey();
|
||||
if (!apiKey.equals(value)) {
|
||||
results[threadIndex] = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
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