test: 提升ShareTrackingService测试覆盖率到100% - 新增3个边界测试
- 新增空白referer和userAgent的转化漏斗测试
- 新增null IP和null params的指标测试
- 新增null params的点击记录测试
覆盖率提升:
- ShareTrackingService: 82% → 100% (+18%) ✨
- Service包: 87% → 89% (+2%)
- 总体分支覆盖率: 64.5% → 65.3% (+0.8%)
- 新增覆盖分支: 5个
- 距离70%目标: 还需29个分支
This commit is contained in:
@@ -105,7 +105,9 @@
|
|||||||
"Bash(mvn test -Dtest=ActivityServiceCoverageTest 2>&1 | tail -30)",
|
"Bash(mvn test -Dtest=ActivityServiceCoverageTest 2>&1 | tail -30)",
|
||||||
"Bash(mvn test -Dtest=ApiKeyEncryptionServiceTest -q)",
|
"Bash(mvn test -Dtest=ApiKeyEncryptionServiceTest -q)",
|
||||||
"Bash(grep -E \"Tests run:|BUILD\" target/surefire-reports/*.txt 2>/dev/null | tail -5 || echo \"检查测试结果...\")",
|
"Bash(grep -E \"Tests run:|BUILD\" target/surefire-reports/*.txt 2>/dev/null | tail -5 || echo \"检查测试结果...\")",
|
||||||
"Bash(git add -A && git commit -m \"test: 提升ApiKeyEncryptionService测试覆盖率 - 新增4个边界测试\n\n- 新增legacy默认密钥在生产环境的测试\n- 新增空白密钥在生产环境的测试\n- 新增environment为null的场景测试\n- 新增非生产环境允许默认密钥的测试\n\n覆盖率提升:\n- ApiKeyEncryptionService: 73% → 84% \\(+11%\\)\n- Service包: 86% → 87% \\(+1%\\)\n- 总体分支覆盖率: 64.1% → 64.5% \\(+0.4%\\)\n- 新增覆盖分支: 3个\n- 距离70%目标: 还需34个分支\")"
|
"Bash(git add -A && git commit -m \"test: 提升ApiKeyEncryptionService测试覆盖率 - 新增4个边界测试\n\n- 新增legacy默认密钥在生产环境的测试\n- 新增空白密钥在生产环境的测试\n- 新增environment为null的场景测试\n- 新增非生产环境允许默认密钥的测试\n\n覆盖率提升:\n- ApiKeyEncryptionService: 73% → 84% \\(+11%\\)\n- Service包: 86% → 87% \\(+1%\\)\n- 总体分支覆盖率: 64.1% → 64.5% \\(+0.4%\\)\n- 新增覆盖分支: 3个\n- 距离70%目标: 还需34个分支\")",
|
||||||
|
"Bash(mvn test -Dtest=ShareTrackingServiceTest -q)",
|
||||||
|
"Bash(git add -A && git commit -m \"test: 提升ShareTrackingService测试覆盖率到100% - 新增3个边界测试\n\n- 新增空白referer和userAgent的转化漏斗测试\n- 新增null IP和null params的指标测试\n- 新增null params的点击记录测试\n\n覆盖率提升:\n- ShareTrackingService: 82% → 100% \\(+18%\\) ✨\n- Service包: 87% → 89% \\(+2%\\)\n- 总体分支覆盖率: 64.5% → 65.3% \\(+0.8%\\)\n- 新增覆盖分支: 5个\n- 距离70%目标: 还需29个分支\")"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,4 +323,97 @@ class ShareTrackingServiceTest {
|
|||||||
click.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
click.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
return click;
|
return click;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("获取转化漏斗 - 处理空白referer和userAgent")
|
||||||
|
void shouldHandleBlankRefererAndUserAgent_InConversionFunnel() {
|
||||||
|
// Given
|
||||||
|
OffsetDateTime startTime = OffsetDateTime.now(ZoneOffset.UTC).minusDays(1);
|
||||||
|
OffsetDateTime endTime = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
List<LinkClickEntity> clicks = new ArrayList<>();
|
||||||
|
|
||||||
|
LinkClickEntity click1 = new LinkClickEntity();
|
||||||
|
click1.setCode(SHORT_CODE);
|
||||||
|
click1.setIp(IP);
|
||||||
|
click1.setUserAgent(" "); // blank userAgent
|
||||||
|
click1.setReferer(" "); // blank referer
|
||||||
|
click1.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
LinkClickEntity click2 = new LinkClickEntity();
|
||||||
|
click2.setCode(SHORT_CODE);
|
||||||
|
click2.setIp(IP);
|
||||||
|
click2.setUserAgent(null); // null userAgent
|
||||||
|
click2.setReferer("https://example.com");
|
||||||
|
click2.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
clicks.add(click1);
|
||||||
|
clicks.add(click2);
|
||||||
|
|
||||||
|
when(linkClickRepository.findByActivityIdAndCreatedAtBetween(ACTIVITY_ID, startTime, endTime))
|
||||||
|
.thenReturn(clicks);
|
||||||
|
|
||||||
|
// When
|
||||||
|
Map<String, Object> result = shareTrackingService.getConversionFunnel(ACTIVITY_ID, startTime, endTime);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(2L, result.get("totalClicks"));
|
||||||
|
assertEquals(1L, result.get("withReferer")); // only click2 has non-blank referer
|
||||||
|
assertEquals(0L, result.get("withUserAgent")); // both are null or blank
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("获取分享指标 - 处理null IP和null params")
|
||||||
|
void shouldHandleNullIpAndNullParams_InMetrics() {
|
||||||
|
// Given
|
||||||
|
OffsetDateTime startTime = OffsetDateTime.now(ZoneOffset.UTC).minusDays(1);
|
||||||
|
OffsetDateTime endTime = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
|
|
||||||
|
List<LinkClickEntity> clicks = new ArrayList<>();
|
||||||
|
|
||||||
|
LinkClickEntity click1 = new LinkClickEntity();
|
||||||
|
click1.setCode(SHORT_CODE);
|
||||||
|
click1.setIp(null); // null IP
|
||||||
|
click1.setUserAgent(USER_AGENT);
|
||||||
|
click1.setParams(null); // null params
|
||||||
|
click1.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
LinkClickEntity click2 = new LinkClickEntity();
|
||||||
|
click2.setCode(SHORT_CODE);
|
||||||
|
click2.setIp("192.168.1.1");
|
||||||
|
click2.setUserAgent(USER_AGENT);
|
||||||
|
click2.setParams(null); // null params
|
||||||
|
click2.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
|
||||||
|
clicks.add(click1);
|
||||||
|
clicks.add(click2);
|
||||||
|
|
||||||
|
when(linkClickRepository.findByActivityIdAndCreatedAtBetween(ACTIVITY_ID, startTime, endTime))
|
||||||
|
.thenReturn(clicks);
|
||||||
|
|
||||||
|
// When
|
||||||
|
ShareMetricsResponse result = shareTrackingService.getShareMetrics(ACTIVITY_ID, startTime, endTime);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(2L, result.getTotalClicks());
|
||||||
|
assertEquals(1L, result.getUniqueVisitors()); // only click2 has IP
|
||||||
|
|
||||||
|
// Both clicks should have "unknown" source due to null params
|
||||||
|
Map<String, Long> expectedSources = Map.of("unknown", 2L);
|
||||||
|
assertEquals(expectedSources, result.getSourceDistribution());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("记录点击 - 处理null params不抛异常")
|
||||||
|
void shouldHandleNullParams_WhenRecordClick() {
|
||||||
|
// When
|
||||||
|
shareTrackingService.recordClick(SHORT_CODE, IP, USER_AGENT, REFERER, null);
|
||||||
|
|
||||||
|
// Then
|
||||||
|
verify(linkClickRepository).save(argThat(entity -> {
|
||||||
|
assertEquals(SHORT_CODE, entity.getCode());
|
||||||
|
assertNull(entity.getParams()); // params should remain null
|
||||||
|
return true;
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user