package com.tourguide.modules.user.service; import com.tourguide.common.exception.BusinessException; import com.tourguide.integration.sms.SmsCodeSender; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import java.time.Duration; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class GuideVerificationCodeServiceTest { private StringRedisTemplate redisTemplate; private ValueOperations valueOperations; private SmsCodeSender smsCodeSender; private GuideVerificationCodeService service; @SuppressWarnings("unchecked") @BeforeEach void setUp() { redisTemplate = mock(StringRedisTemplate.class); valueOperations = mock(ValueOperations.class); smsCodeSender = mock(SmsCodeSender.class); when(redisTemplate.opsForValue()).thenReturn(valueOperations); service = new GuideVerificationCodeService(redisTemplate, smsCodeSender, "123456"); } @Test void shouldStoreFixedDevelopmentCode() { when(redisTemplate.hasKey(any())).thenReturn(false); service.send("13800138000"); verify(valueOperations).set(eq("tourguide:guide-login:code:13800138000"), eq("123456"), eq(Duration.ofMinutes(5))); verify(valueOperations).set(eq("tourguide:guide-login:cooldown:13800138000"), eq("1"), eq(Duration.ofSeconds(30))); } @Test void shouldConsumeValidCode() { service.verifyAndConsume("13800138000", "123456"); verify(redisTemplate).delete("tourguide:guide-login:code:13800138000"); } @Test void shouldIsolatePhoneChangeCodeFromLoginCode() { when(redisTemplate.hasKey(any())).thenReturn(false); service.send("13800138000", "change-old"); verify(valueOperations).set(eq("tourguide:guide-login:code:change-old:13800138000"), eq("123456"), eq(Duration.ofMinutes(5))); verify(valueOperations).set(eq("tourguide:guide-login:cooldown:change-old:13800138000"), eq("1"), eq(Duration.ofSeconds(30))); } @Test void shouldRejectInvalidCode() { when(valueOperations.get(any())).thenReturn("123456"); Throwable error = org.assertj.core.api.Assertions.catchThrowable( () -> service.verifyAndConsume("13800138000", "000000")); assertThat(error) .isInstanceOf(BusinessException.class) .hasMessage("验证码错误或已过期") .extracting("code") .isEqualTo(400); } }