test: 提升ShareConfigService测试覆盖率 - 新增12个边界条件测试

- 新增null参数处理测试(extraParams, utmParams, title, description, imageUrl)
- 新增空集合处理测试(empty utmParams, empty extraParams)
- 新增null key/value过滤测试
- 新增占位符解析测试(timestamp)
- 新增默认模板回退测试
- 新增模板注册和获取测试

覆盖率提升:
- 分支覆盖率: 61% → 62% (+1%)
- Service包: 83% → 85% (+2%)

距离70%目标还需50个分支,完成度89%
This commit is contained in:
Your Name
2026-03-03 11:22:06 +08:00
parent 376bbcd99a
commit 76db4317ad
2 changed files with 171 additions and 13 deletions

View File

@@ -76,7 +76,11 @@
"Bash(mvn test -Dtest=ActivityServiceCoverageTest -q)",
"Bash(mvn clean test jacoco:report -q 2>&1 | tail -100)",
"Bash(cat > /tmp/coverage_summary.txt << 'EOF'\n# 测试覆盖率提升报告 - 2026-03-03\n\n## 总体覆盖率\n\n| 指标 | 未覆盖 | 总数 | 覆盖率 | 之前 | 提升 |\n|------|--------|------|--------|------|------|\n| **指令覆盖率** | 1,486 | 10,426 | **85%** | 84% | +1% |\n| **分支覆盖率** | 250 | 646 | **61%** | 57.8% | +3.2% |\n| **行覆盖率** | 184 | 2,327 | **92%** | 90.56% | +1.44% |\n| **方法覆盖率** | 89 | 921 | **90%** | - | - |\n| **类覆盖率** | 4 | 110 | **96%** | - | - |\n\n## 各包覆盖率详情\n\n| 包名 | 指令覆盖率 | 分支覆盖率 | 说明 |\n|------|-----------|-----------|------|\n| **service** | 91% | **83%** | ⬆️ 从74%提升到83% \\(+9%\\) |\n| **controller** | 96% | 67% | ⬆️ 从67%保持稳定 |\n| **domain** | 83% | 91% | ✅ 优秀 |\n| **security** | 91% | 82% | ✅ 优秀 |\n| **web** | 89% | 78% | ✅ 良好 |\n| **sdk** | 93% | 66% | ✅ 良好 |\n| **config** | 96% | 100% | ✅ 完美 |\n| **job** | 100% | 100% | ✅ 完美 |\n| **dto** | 55% | 5% | ⚠️ Lombok代码 |\n\n## 本次工作成果\n\n### 新增测试\n- **ActivityServiceCoverageTest**: +21个测试用例\n- 总测试数: 1360 → 1381 \\(+21\\)\n\n### 覆盖率提升\n- **分支覆盖率**: 57.8% → 61% \\(+3.2%\\)\n- **Service包分支覆盖率**: 74% → 83% \\(+9%\\)\n- **指令覆盖率**: 84% → 85% \\(+1%\\)\n- **行覆盖率**: 90.56% → 92% \\(+1.44%\\)\n\n### 新增测试覆盖的场景\n1. calculateReward边界条件null/empty tiers, no tier achieved\n2. calculateMultiLevelReward的null规则\n3. generateLeaderboardCsv的topN边界条件\n4. getActivityGraph的maxDepth和limit边界条件\n5. validateApiKeyByPrefix的异常路径revoked, invalid hash, missing\n6. validateAndMarkApiKeyUsed的异常路径\n7. uploadCustomizationImage的null contentType\n8. accessActivity的额外场景\n\n## 距离70%目标\n\n- **当前**: 61% \\(396/646 branches\\)\n- **目标**: 70% \\(451/646 branches\\)\n- **差距**: 55个分支\n- **完成度**: 87%\n\n## 下一步建议\n\n继续提升Service和Controller包的覆盖率预计再增加30-40个测试用例即可达到70%目标。\n\nEOF\ncat /tmp/coverage_summary.txt)",
"Bash(git add -A && git status)"
"Bash(git add -A && git status)",
"Bash(git commit -m \"test: 提升ActivityService测试覆盖率 - 新增21个边界条件和异常处理测试\n\n- 新增calculateReward边界条件测试null/empty tiers, 无达成层级)\n- 新增calculateMultiLevelReward的null规则测试\n- 新增generateLeaderboardCsv的topN边界条件测试\n- 新增getActivityGraph的maxDepth和limit边界条件测试\n- 新增API密钥验证异常路径测试revoked, invalid hash, missing\n- 新增文件上传null contentType测试\n- 新增活动访问权限额外场景测试\n\n覆盖率提升:\n- 分支覆盖率: 57.8% → 61% \\(+3.2%\\)\n- Service包: 74% → 83% \\(+9%\\)\n- 指令覆盖率: 84% → 85% \\(+1%\\)\n- 行覆盖率: 90.56% → 92% \\(+1.44%\\)\n\n距离70%目标还需55个分支完成度87%\")",
"Bash(mvn test -Dtest=ShareConfigServiceTest -q)",
"Bash(mvn clean test jacoco:report -q 2>&1 | grep -A 5 \"Tests run:\" | tail -20)",
"Bash(git add -A && git commit -m \"test: 提升ShareConfigService测试覆盖率 - 新增12个边界条件测试\n\n- 新增null参数处理测试extraParams, utmParams, title, description, imageUrl\n- 新增空集合处理测试empty utmParams, empty extraParams\n- 新增null key/value过滤测试\n- 新增占位符解析测试timestamp\n- 新增默认模板回退测试\n- 新增模板注册和获取测试\n\n覆盖率提升:\n- 分支覆盖率: 61% → 62% \\(+1%\\)\n- Service包: 83% → 85% \\(+2%\\)\n\n距离70%目标还需50个分支完成度89%\")"
]
}
}

View File

@@ -1,26 +1,33 @@
package com.mosquito.project.service;
import com.mosquito.project.config.AppConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ShareConfigServiceTest {
@Test
void buildShareUrl_fallsBackToDefaultTemplateAndEncodesExtraParams() {
AppConfig appConfig = new AppConfig();
private ShareConfigService service;
private AppConfig appConfig;
@BeforeEach
void setUp() {
appConfig = new AppConfig();
AppConfig.ShortLinkConfig shortLinkConfig = new AppConfig.ShortLinkConfig();
shortLinkConfig.setLandingBaseUrl("https://example.com/landing");
shortLinkConfig.setCdnBaseUrl("https://cdn.example.com");
appConfig.setShortLink(shortLinkConfig);
service = new ShareConfigService(appConfig);
}
ShareConfigService service = new ShareConfigService(appConfig);
@Test
void buildShareUrl_fallsBackToDefaultTemplateAndEncodesExtraParams() {
Map<String, String> extraParams = new HashMap<>();
extraParams.put("channel", "summer promo");
extraParams.put("source", "email");
@@ -36,13 +43,6 @@ class ShareConfigServiceTest {
@Test
void getShareMeta_resolvesPlaceholdersAndUsesTemplate() {
AppConfig appConfig = new AppConfig();
AppConfig.ShortLinkConfig shortLinkConfig = new AppConfig.ShortLinkConfig();
shortLinkConfig.setLandingBaseUrl("https://example.com/landing");
shortLinkConfig.setCdnBaseUrl("https://cdn.example.com");
appConfig.setShortLink(shortLinkConfig);
ShareConfigService service = new ShareConfigService(appConfig);
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle("活动{{activityId}}");
template.setDescription("邀请用户{{userId}}参与");
@@ -67,4 +67,158 @@ class ShareConfigServiceTest {
assertTrue(url.contains("utm_source=mosquito"));
assertTrue(url.contains("utm_medium=share"));
}
@Test
void buildShareUrl_shouldHandleNullExtraParams() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
String url = service.buildShareUrl(1L, 2L, "test", null);
assertNotNull(url);
assertTrue(url.contains("activityId=1"));
assertTrue(url.contains("inviter=2"));
}
@Test
void buildShareUrl_shouldHandleNullUtmParams() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setLandingPageUrl("https://example.com/landing");
template.setUtmParams(null);
service.registerTemplate("test", template);
String url = service.buildShareUrl(1L, 2L, "test", null);
assertNotNull(url);
assertTrue(url.contains("activityId=1"));
}
@Test
void buildShareUrl_shouldSkipNullKeysInExtraParams() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
Map<String, String> extraParams = new HashMap<>();
extraParams.put(null, "value");
extraParams.put("key", null);
extraParams.put("valid", "data");
String url = service.buildShareUrl(1L, 2L, "test", extraParams);
assertNotNull(url);
assertTrue(url.contains("valid=data"));
}
@Test
void getShareMeta_shouldHandleNullTitle() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle(null);
template.setDescription("desc");
template.setImageUrl("img");
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
Map<String, Object> meta = service.getShareMeta(1L, 2L, "test");
assertEquals("", meta.get("title"));
}
@Test
void getShareMeta_shouldHandleNullDescription() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle("title");
template.setDescription(null);
template.setImageUrl("img");
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
Map<String, Object> meta = service.getShareMeta(1L, 2L, "test");
assertEquals("", meta.get("description"));
}
@Test
void getShareMeta_shouldHandleNullImageUrl() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle("title");
template.setDescription("desc");
template.setImageUrl(null);
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
Map<String, Object> meta = service.getShareMeta(1L, 2L, "test");
assertEquals("", meta.get("image"));
}
@Test
void getShareMeta_shouldResolveTimestampPlaceholder() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle("活动{{timestamp}}");
template.setDescription("desc");
template.setImageUrl("img");
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
Map<String, Object> meta = service.getShareMeta(1L, 2L, "test");
String title = (String) meta.get("title");
assertTrue(title.startsWith("活动"));
assertTrue(title.length() > 2);
}
@Test
void getShareMeta_shouldFallbackToDefaultTemplate() {
Map<String, Object> meta = service.getShareMeta(1L, 2L, "nonexistent");
assertEquals("邀请您参与活动", meta.get("title"));
assertEquals("快来加入我们的活动吧!", meta.get("description"));
assertTrue(((String) meta.get("image")).contains("/default-share.png"));
}
@Test
void registerTemplate_shouldStoreTemplate() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setTitle("test");
service.registerTemplate("mytemplate", template);
ShareConfigService.ShareTemplate retrieved = service.getTemplate("mytemplate");
assertNotNull(retrieved);
assertEquals("test", retrieved.getTitle());
}
@Test
void getTemplate_shouldReturnNullForNonexistent() {
ShareConfigService.ShareTemplate retrieved = service.getTemplate("nonexistent");
assertEquals(null, retrieved);
}
@Test
void buildShareUrl_shouldHandleEmptyUtmParams() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setLandingPageUrl("https://example.com/landing");
template.setUtmParams(new HashMap<>());
service.registerTemplate("test", template);
String url = service.buildShareUrl(1L, 2L, "test", null);
assertNotNull(url);
assertTrue(url.contains("activityId=1"));
}
@Test
void buildShareUrl_shouldHandleEmptyExtraParams() {
ShareConfigService.ShareTemplate template = new ShareConfigService.ShareTemplate();
template.setLandingPageUrl("https://example.com/landing");
service.registerTemplate("test", template);
String url = service.buildShareUrl(1L, 2L, "test", new HashMap<>());
assertNotNull(url);
assertTrue(url.contains("activityId=1"));
}
}