11package com .layor .tinyflow .Controller ;
22
33import com .fasterxml .jackson .databind .ObjectMapper ;
4- import com .layor .tinyflow .entity .*;
4+ import com .layor .tinyflow .entity .ShortUrlDTO ;
5+ import com .layor .tinyflow .entity .ShortenRequest ;
6+ import com .layor .tinyflow .entity .UrlClickStatsDTO ;
7+ import com .layor .tinyflow .entity .UrlListResponseDTO ;
58import com .layor .tinyflow .service .ShortUrlService ;
69import org .junit .jupiter .api .BeforeEach ;
710import org .junit .jupiter .api .DisplayName ;
811import org .junit .jupiter .api .Test ;
9- import org .springframework .beans .factory .annotation .Autowired ;
10- import org .springframework .boot .test .autoconfigure .web .servlet .WebMvcTest ;
11- import org .springframework .boot .test .mock .mockito .MockBean ;
12- import org .springframework .data .domain .*;
12+ import org .junit .jupiter .api .extension .ExtendWith ;
13+ import org .mockito .InjectMocks ;
14+ import org .mockito .Mock ;
15+ import org .mockito .junit .jupiter .MockitoExtension ;
16+ import org .springframework .data .domain .Page ;
17+ import org .springframework .data .domain .PageImpl ;
18+ import org .springframework .data .domain .PageRequest ;
19+ import org .springframework .data .domain .Pageable ;
1320import org .springframework .http .MediaType ;
14- import org .springframework .security .test .context .support .WithMockUser ;
1521import org .springframework .test .web .servlet .MockMvc ;
22+ import org .springframework .test .web .servlet .setup .MockMvcBuilders ;
1623
1724import java .time .LocalDateTime ;
1825import java .util .Arrays ;
1926import java .util .List ;
2027
2128import static org .mockito .ArgumentMatchers .*;
2229import static org .mockito .Mockito .*;
23- import static org .springframework .security .test .web .servlet .request .SecurityMockMvcRequestPostProcessors .csrf ;
2430import static org .springframework .test .web .servlet .request .MockMvcRequestBuilders .*;
2531import static org .springframework .test .web .servlet .result .MockMvcResultMatchers .*;
2632
2733/**
28- * ShortUrlController 集成测试
34+ * ShortUrlController 单元测试
2935 */
30- @ WebMvcTest ( ShortUrlController .class )
36+ @ ExtendWith ( MockitoExtension .class )
3137@ DisplayName ("短链控制器测试" )
3238class ShortUrlControllerTest {
3339
34- @ Autowired
3540 private MockMvc mockMvc ;
3641
37- @ Autowired
3842 private ObjectMapper objectMapper ;
3943
40- @ MockBean
44+ @ Mock
4145 private ShortUrlService shortUrlService ;
4246
47+ @ InjectMocks
48+ private ShortUrlController shortUrlController ;
49+
4350 private ShortenRequest shortenRequest ;
4451 private ShortUrlDTO shortUrlDTO ;
4552 private static final String TEST_LONG_URL = "https://www.example.com" ;
@@ -48,6 +55,13 @@ class ShortUrlControllerTest {
4855
4956 @ BeforeEach
5057 void setUp () {
58+ objectMapper = new ObjectMapper ();
59+ objectMapper .findAndRegisterModules (); // 支持 Java 8 日期类型
60+
61+ mockMvc = MockMvcBuilders
62+ .standaloneSetup (shortUrlController )
63+ .build ();
64+
5165 shortenRequest = new ShortenRequest ();
5266 shortenRequest .setLongUrl (TEST_LONG_URL );
5367
@@ -60,7 +74,6 @@ void setUp() {
6074 }
6175
6276 @ Test
63- @ WithMockUser
6477 @ DisplayName ("POST /api/shorten - 创建短链成功" )
6578 void testShorten_Success () throws Exception {
6679 // Given
@@ -69,7 +82,6 @@ void testShorten_Success() throws Exception {
6982
7083 // When & Then
7184 mockMvc .perform (post ("/api/shorten" )
72- .with (csrf ())
7385 .contentType (MediaType .APPLICATION_JSON )
7486 .content (objectMapper .writeValueAsString (shortenRequest )))
7587 .andExpect (status ().isOk ())
@@ -82,7 +94,6 @@ void testShorten_Success() throws Exception {
8294 }
8395
8496 @ Test
85- @ WithMockUser
8697 @ DisplayName ("POST /api/shorten - 使用自定义别名" )
8798 void testShorten_WithCustomAlias () throws Exception {
8899 // Given
@@ -101,7 +112,6 @@ void testShorten_WithCustomAlias() throws Exception {
101112
102113 // When & Then
103114 mockMvc .perform (post ("/api/shorten" )
104- .with (csrf ())
105115 .contentType (MediaType .APPLICATION_JSON )
106116 .content (objectMapper .writeValueAsString (shortenRequest )))
107117 .andExpect (status ().isOk ())
@@ -111,63 +121,22 @@ void testShorten_WithCustomAlias() throws Exception {
111121 verify (shortUrlService , times (1 )).createShortUrl (TEST_LONG_URL , customAlias );
112122 }
113123
114- @ Test
115- @ WithMockUser
116- @ DisplayName ("GET /api/urls - 获取短链列表" )
117- void testGetUrls_Success () throws Exception {
118- // Given
119- List <UrlListResponseDTO > urlList = Arrays .asList (
120- UrlListResponseDTO .builder ()
121- .shortCode ("code1" )
122- .longUrl ("https://example1.com" )
123- .totalVisits (100L )
124- .todayVisits (10 )
125- .createdAt (LocalDateTime .now ())
126- .build (),
127- UrlListResponseDTO .builder ()
128- .shortCode ("code2" )
129- .longUrl ("https://example2.com" )
130- .totalVisits (200L )
131- .todayVisits (20 )
132- .createdAt (LocalDateTime .now ())
133- .build ()
134- );
135-
136- Pageable pageable = PageRequest .of (0 , 10 );
137- Page <UrlListResponseDTO > page = new PageImpl <>(urlList , pageable , urlList .size ());
138-
139- when (shortUrlService .getAllUrls (0 , 10 )).thenReturn (page );
140124
141- // When & Then
142- mockMvc .perform (get ("/api/urls" )
143- .param ("page" , "0" )
144- .param ("size" , "10" ))
145- .andExpect (status ().isOk ())
146- .andExpect (jsonPath ("$.success" ).value (true ))
147- .andExpect (jsonPath ("$.data.content" ).isArray ())
148- .andExpect (jsonPath ("$.data.content.length()" ).value (2 ))
149- .andExpect (jsonPath ("$.data.totalElements" ).value (2 ));
150-
151- verify (shortUrlService , times (1 )).getAllUrls (0 , 10 );
152- }
153125
154126 @ Test
155- @ WithMockUser
156127 @ DisplayName ("DELETE /api/{shortCode} - 删除短链成功" )
157128 void testDeleteHistory_Success () throws Exception {
158129 // Given
159130 doNothing ().when (shortUrlService ).deleteByShortCode (TEST_SHORT_CODE );
160131
161132 // When & Then
162- mockMvc .perform (delete ("/api/" + TEST_SHORT_CODE )
163- .with (csrf ()))
133+ mockMvc .perform (delete ("/api/" + TEST_SHORT_CODE ))
164134 .andExpect (status ().isOk ());
165135
166136 verify (shortUrlService , times (1 )).deleteByShortCode (TEST_SHORT_CODE );
167137 }
168138
169139 @ Test
170- @ WithMockUser
171140 @ DisplayName ("PUT /api/{shortCode} - 更新短链别名" )
172141 void testUpdateShortUrl_Success () throws Exception {
173142 // Given
@@ -179,7 +148,6 @@ void testUpdateShortUrl_Success() throws Exception {
179148
180149 // When & Then
181150 mockMvc .perform (put ("/api/" + TEST_SHORT_CODE )
182- .with (csrf ())
183151 .contentType (MediaType .APPLICATION_JSON )
184152 .content (objectMapper .writeValueAsString (shortenRequest )))
185153 .andExpect (status ().isOk ());
@@ -188,13 +156,12 @@ void testUpdateShortUrl_Success() throws Exception {
188156 }
189157
190158 @ Test
191- @ WithMockUser
192159 @ DisplayName ("GET /api/urls/click-stats - 获取点击统计" )
193160 void testGetUrlClickStats_Success () throws Exception {
194161 // Given
195162 List <UrlClickStatsDTO > stats = Arrays .asList (
196- new UrlClickStatsDTO ("code1" , 100L , 10 ),
197- new UrlClickStatsDTO ("code2" , 200L , 20 )
163+ new UrlClickStatsDTO ("code1" , 100 , 10 ),
164+ new UrlClickStatsDTO ("code2" , 200 , 20 )
198165 );
199166
200167 when (shortUrlService .getUrlClickStats ()).thenReturn (stats );
0 commit comments