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:
Your Name
2026-03-02 13:31:54 +08:00
parent 32d6449ea4
commit 91a0b77f7a
2272 changed files with 221995 additions and 503 deletions

View File

@@ -0,0 +1,177 @@
package com.mosquito.project.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mosquito.project.persistence.entity.ShortLinkEntity;
import com.mosquito.project.persistence.entity.UserInviteEntity;
import com.mosquito.project.persistence.repository.UserInviteRepository;
import com.mosquito.project.service.PosterRenderService;
import com.mosquito.project.service.ShareConfigService;
import com.mosquito.project.service.ShortLinkService;
import com.mosquito.project.support.TestAuthSupport;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@WebMvcTest(UserExperienceController.class)
@Import(com.mosquito.project.config.ControllerTestConfig.class)
@TestPropertySource(properties = {
"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration," +
"org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration," +
"org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
})
class UserExperienceControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private ShortLinkService shortLinkService;
@MockBean
private UserInviteRepository userInviteRepository;
@MockBean
private PosterRenderService posterRenderService;
@MockBean
private ShareConfigService shareConfigService;
@MockBean
private com.mosquito.project.persistence.repository.UserRewardRepository userRewardRepository;
@Test
void shouldReturnInvitationInfo_withShortLink() throws Exception {
ShortLinkEntity e = new ShortLinkEntity();
e.setCode("inv12345");
e.setOriginalUrl("https://example.com/landing?activityId=1&inviter=2");
when(shortLinkService.create(anyString())).thenReturn(e);
when(shareConfigService.buildShareUrl(anyLong(), anyLong(), anyString(), any())).thenReturn("https://example.com/landing?activityId=1&inviter=2");
mockMvc.perform(get("/api/v1/me/invitation-info")
.param("activityId", "1")
.param("userId", "2")
.accept(MediaType.APPLICATION_JSON)
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.code").value("inv12345"))
.andExpect(jsonPath("$.data.path").value("/r/inv12345"));
}
@Test
void shouldReturnInvitedFriends_withPagination() throws Exception {
UserInviteEntity a = new UserInviteEntity(); a.setInviteeUserId(10L); a.setStatus("clicked");
UserInviteEntity b = new UserInviteEntity(); b.setInviteeUserId(11L); b.setStatus("registered");
UserInviteEntity c = new UserInviteEntity(); c.setInviteeUserId(12L); c.setStatus("ordered");
when(userInviteRepository.findByActivityIdAndInviterUserId(anyLong(), anyLong())).thenReturn(List.of(a,b,c));
mockMvc.perform(get("/api/v1/me/invited-friends")
.param("activityId", "1")
.param("userId", "2")
.param("page", "1")
.param("size", "1")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data[0].status").value("registered"));
}
@Test
void shouldReturnPosterImage() throws Exception {
when(posterRenderService.renderPoster(anyLong(), anyLong(), anyString())).thenReturn("placeholder".getBytes());
mockMvc.perform(get("/api/v1/me/poster/image")
.param("activityId", "1")
.param("userId", "2")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(header().string("Content-Type", "image/png"));
}
@Test
void posterImage_shouldReturn500_whenRenderFails() throws Exception {
when(posterRenderService.renderPoster(anyLong(), anyLong(), anyString()))
.thenThrow(new RuntimeException("render failed"));
mockMvc.perform(get("/api/v1/me/poster/image")
.param("activityId", "1")
.param("userId", "2")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isInternalServerError());
}
@Test
void shouldReturnPosterConfig() throws Exception {
mockMvc.perform(get("/api/v1/me/poster/config")
.param("template", "default")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.template").value("default"));
}
@Test
void shouldReturnPosterHtml() throws Exception {
when(posterRenderService.renderPosterHtml(anyLong(), anyLong(), anyString())).thenReturn("<html></html>");
mockMvc.perform(get("/api/v1/me/poster/html")
.param("activityId", "1")
.param("userId", "2")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML));
}
@Test
void posterHtml_shouldReturn500_whenRenderFails() throws Exception {
when(posterRenderService.renderPosterHtml(anyLong(), anyLong(), anyString()))
.thenThrow(new RuntimeException("render failed"));
mockMvc.perform(get("/api/v1/me/poster/html")
.param("activityId", "1")
.param("userId", "2")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isInternalServerError());
}
@Test
void shouldReturnRewards_withPagination() throws Exception {
var r1 = new com.mosquito.project.persistence.entity.UserRewardEntity(); r1.setType("points"); r1.setPoints(100); r1.setCreatedAt(java.time.OffsetDateTime.now());
var r2 = new com.mosquito.project.persistence.entity.UserRewardEntity(); r2.setType("coupon"); r2.setPoints(0); r2.setCreatedAt(java.time.OffsetDateTime.now().minusDays(1));
when(userRewardRepository.findByActivityIdAndUserIdOrderByCreatedAtDesc(anyLong(), anyLong())).thenReturn(java.util.List.of(r1, r2));
mockMvc.perform(get("/api/v1/me/rewards")
.param("activityId", "1")
.param("userId", "2")
.param("page", "0")
.param("size", "1")
.header("X-API-Key", TestAuthSupport.RAW_API_KEY)
.header("Authorization", "Bearer test-token"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data[0].type").value("points"));
}
}