test(web): add edge case tests for interceptors

- Add inactive token test for UserAuthInterceptor (line 27)
- Add 1xx status code test for ApiResponseWrapperInterceptor (line 31)
- Add production profile and Redis null tests for RateLimitInterceptor

Coverage improvement: Web package 83% -> 85% (92/108 branches)
Overall: 66% (429/646 branches), +2 branches from previous commit
This commit is contained in:
Your Name
2026-03-04 09:58:38 +08:00
parent c50e32d9e5
commit 0b9d82c8d3
4 changed files with 101 additions and 2 deletions

View File

@@ -200,4 +200,17 @@ class ApiResponseWrapperInterceptorTest {
// Then
verify(response, never()).setHeader(anyString(), anyString());
}
@Test
@DisplayName("postHandle不应该为1xx信息响应设置版本头")
void shouldNotSetVersionHeader_whenResponseIsInformational() {
// Given - 100 Continue
when(response.getStatus()).thenReturn(100);
// When
interceptor.postHandle(request, response, handler, modelAndView);
// Then
verify(response, never()).setHeader(anyString(), anyString());
}
}

View File

@@ -231,7 +231,7 @@ class RateLimitInterceptorTest {
Environment environment = mock(Environment.class);
StringRedisTemplate redisTemplate = mock(StringRedisTemplate.class);
ValueOperations<String, String> valueOperations = mock(ValueOperations.class);
given(environment.getActiveProfiles()).willReturn(new String[]{"dev"});
given(environment.getProperty("app.rate-limit.per-minute", "100")).willReturn("100");
given(redisTemplate.opsForValue()).willReturn(valueOperations);
@@ -250,4 +250,45 @@ class RateLimitInterceptorTest {
// Then
assertThat(result).isTrue();
}
@Test
@DisplayName("应识别production配置文件为生产模式")
void shouldRecognizeProductionProfile() {
// Given
Environment environment = mock(Environment.class);
StringRedisTemplate redisTemplate = mock(StringRedisTemplate.class);
given(environment.getActiveProfiles()).willReturn(new String[]{"production"});
given(environment.getProperty("app.rate-limit.per-minute", "100")).willReturn("100");
// When & Then - 不应抛出异常
RateLimitInterceptor interceptor = new RateLimitInterceptor(environment, redisTemplate);
assertThat(interceptor).isNotNull();
}
@Test
@DisplayName("Redis返回null时应使用默认值1")
void shouldUseDefaultValue_whenRedisReturnsNull() {
// Given
Environment environment = mock(Environment.class);
StringRedisTemplate redisTemplate = mock(StringRedisTemplate.class);
ValueOperations<String, String> valueOperations = mock(ValueOperations.class);
given(environment.getActiveProfiles()).willReturn(new String[]{"dev"});
given(environment.getProperty("app.rate-limit.per-minute", "100")).willReturn("100");
given(redisTemplate.opsForValue()).willReturn(valueOperations);
given(valueOperations.increment(anyString())).willReturn(null); // Redis返回null
RateLimitInterceptor interceptor = new RateLimitInterceptor(environment, redisTemplate);
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("X-API-Key", API_KEY);
MockHttpServletResponse response = new MockHttpServletResponse();
// When
boolean result = interceptor.preHandle(request, response, new Object());
// Then
assertThat(result).isTrue();
assertThat(response.getHeader("X-RateLimit-Remaining")).isEqualTo("99");
}
}

View File

@@ -1,6 +1,7 @@
package com.mosquito.project.web;
import com.mosquito.project.config.AppConfig;
import com.mosquito.project.security.IntrospectionResponse;
import com.mosquito.project.security.UserIntrospectionService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -12,6 +13,9 @@ import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class UserAuthInterceptorTest {
@@ -28,4 +32,39 @@ class UserAuthInterceptorTest {
assertFalse(result);
assertEquals(401, response.getStatus());
}
@Test
@DisplayName("空白Authorization应拒绝")
void shouldRejectRequest_whenBlankAuthorization() {
UserIntrospectionService service = new UserIntrospectionService(new RestTemplateBuilder(), new AppConfig(), Optional.empty());
UserAuthInterceptor interceptor = new UserAuthInterceptor(service);
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", " "); // 空白
MockHttpServletResponse response = new MockHttpServletResponse();
boolean result = interceptor.preHandle(request, response, new Object());
assertFalse(result);
assertEquals(401, response.getStatus());
}
@Test
@DisplayName("不活跃的token应拒绝")
void shouldRejectRequest_whenTokenIsInactive() {
// Given
UserIntrospectionService service = mock(UserIntrospectionService.class);
when(service.introspect(anyString())).thenReturn(IntrospectionResponse.inactive());
UserAuthInterceptor interceptor = new UserAuthInterceptor(service);
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("Authorization", "Bearer expired-token");
MockHttpServletResponse response = new MockHttpServletResponse();
// When
boolean result = interceptor.preHandle(request, response, new Object());
// Then
assertFalse(result);
assertEquals(401, response.getStatus());
}
}