增加 后端,后台管理系统,uniapp会员端的自动化测试。
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
package cn.novalon.gym.manage.auth.handler;
|
||||
|
||||
import cn.novalon.gym.manage.auth.dto.PhoneCodeLoginDto;
|
||||
import cn.novalon.gym.manage.auth.dto.PhoneLoginDto;
|
||||
import cn.novalon.gym.manage.auth.dto.SendCodeRequest;
|
||||
import cn.novalon.gym.manage.auth.service.PhoneAuthService;
|
||||
import cn.novalon.gym.manage.auth.vo.PhoneLoginVO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.springframework.mock.web.reactive.function.server.MockServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 手机号认证 Handler 单元测试
|
||||
*/
|
||||
class PhoneAuthHandlerTest {
|
||||
|
||||
@Mock
|
||||
private PhoneAuthService phoneAuthService;
|
||||
|
||||
private PhoneAuthHandler handler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
handler = new PhoneAuthHandler(phoneAuthService);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("一键登录 - 正常返回登录信息")
|
||||
void testOneClickLoginSuccess() {
|
||||
PhoneLoginVO vo = PhoneLoginVO.builder()
|
||||
.memberId(1L)
|
||||
.memberNo("GYM001")
|
||||
.phone("138****0001")
|
||||
.accessToken("jwt-token-xxx")
|
||||
.expiresIn(86400)
|
||||
.isNewUser(true)
|
||||
.build();
|
||||
|
||||
when(phoneAuthService.oneClickLogin(any(PhoneLoginDto.class)))
|
||||
.thenReturn(Mono.just(vo));
|
||||
|
||||
Mono<ServerResponse> result = handler.oneClickLogin(
|
||||
MockServerRequest.builder()
|
||||
.body(Mono.just(new PhoneLoginDto())));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> response.statusCode().is2xxSuccessful())
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("发送短信验证码 - 发送成功")
|
||||
void testSendSmsCodeSuccess() {
|
||||
when(phoneAuthService.sendSmsCode("13800000001"))
|
||||
.thenReturn(Mono.just(true));
|
||||
|
||||
PhoneLoginDto dto = new PhoneLoginDto();
|
||||
dto.setPhone("13800000001");
|
||||
|
||||
Mono<ServerResponse> result = handler.sendSmsCode(
|
||||
MockServerRequest.builder()
|
||||
.body(Mono.just(new SendCodeRequest("13800000001"))));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> response.statusCode().is2xxSuccessful())
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("发送短信验证码 - 发送失败(60秒内重复发送)")
|
||||
void testSendSmsCodeRateLimited() {
|
||||
when(phoneAuthService.sendSmsCode("13800000001"))
|
||||
.thenReturn(Mono.just(false));
|
||||
|
||||
Mono<ServerResponse> result = handler.sendSmsCode(
|
||||
MockServerRequest.builder()
|
||||
.body(Mono.just(new SendCodeRequest("13800000001"))));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> response.statusCode().is2xxSuccessful())
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("验证码登录 - 正常登录")
|
||||
void testCodeLoginSuccess() {
|
||||
PhoneLoginVO vo = PhoneLoginVO.builder()
|
||||
.memberId(2L)
|
||||
.memberNo("GYM002")
|
||||
.accessToken("jwt-token-yyy")
|
||||
.expiresIn(86400)
|
||||
.isNewUser(false)
|
||||
.build();
|
||||
|
||||
when(phoneAuthService.codeLogin(any(PhoneCodeLoginDto.class)))
|
||||
.thenReturn(Mono.just(vo));
|
||||
|
||||
PhoneCodeLoginDto loginDto = new PhoneCodeLoginDto();
|
||||
loginDto.setPhone("13800000002");
|
||||
loginDto.setCode("123456");
|
||||
|
||||
Mono<ServerResponse> result = handler.codeLogin(
|
||||
MockServerRequest.builder()
|
||||
.body(Mono.just(loginDto)));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> response.statusCode().is2xxSuccessful())
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("验证码登录 - 验证码错误导致异常")
|
||||
void testCodeLoginWrongCode() {
|
||||
when(phoneAuthService.codeLogin(any(PhoneCodeLoginDto.class)))
|
||||
.thenReturn(Mono.error(new RuntimeException("验证码错误")));
|
||||
|
||||
PhoneCodeLoginDto loginDto = new PhoneCodeLoginDto();
|
||||
loginDto.setPhone("13800000002");
|
||||
loginDto.setCode("000000");
|
||||
|
||||
Mono<ServerResponse> result = handler.codeLogin(
|
||||
MockServerRequest.builder()
|
||||
.body(Mono.just(loginDto)));
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectError(RuntimeException.class)
|
||||
.verify();
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package cn.novalon.gym.manage.auth.service;
|
||||
|
||||
import cn.novalon.gym.manage.auth.config.SmsProperties;
|
||||
import cn.novalon.gym.manage.auth.service.impl.SmsServiceImpl;
|
||||
import cn.novalon.gym.manage.common.constant.RedisKeyConstants;
|
||||
import cn.novalon.gym.manage.common.util.RedisUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 短信服务单元测试
|
||||
*/
|
||||
class SmsServiceImplTest {
|
||||
|
||||
@Mock
|
||||
private SmsProperties smsProperties;
|
||||
|
||||
@Mock
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
private SmsServiceImpl smsService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
objectMapper = new ObjectMapper();
|
||||
smsService = new SmsServiceImpl(smsProperties, redisUtil, objectMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("发送验证码 - 频率限制内重复发送")
|
||||
void testSendVerificationCodeRateLimited() {
|
||||
String phone = "13800000001";
|
||||
String rateLimitKey = RedisKeyConstants.SMS_CODE + phone + ":rate_limit";
|
||||
|
||||
// 最近60秒内已发送
|
||||
long recentTime = System.currentTimeMillis() / 1000;
|
||||
when(redisUtil.get(eq(rateLimitKey), eq(Long.class)))
|
||||
.thenReturn(Mono.just(recentTime));
|
||||
|
||||
Mono<Boolean> result = smsService.sendVerificationCode(phone);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNext(false)
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("发送验证码 - 首次发送(频率限制不触发)")
|
||||
void testSendVerificationCodeFirstTime() {
|
||||
String phone = "13800000002";
|
||||
String rateLimitKey = RedisKeyConstants.SMS_CODE + phone + ":rate_limit";
|
||||
|
||||
// 从未发送过(返回 0,表示很久以前)
|
||||
long oldTime = 0L;
|
||||
when(redisUtil.get(eq(rateLimitKey), eq(Long.class)))
|
||||
.thenReturn(Mono.just(oldTime));
|
||||
|
||||
// 由于会真实调用阿里云API(会失败),mock redis set
|
||||
when(redisUtil.setWithExpire(anyString(), anyLong(), anyLong()))
|
||||
.thenReturn(Mono.just(true));
|
||||
|
||||
Mono<Boolean> result = smsService.sendVerificationCode(phone);
|
||||
// 阿里云API调用会失败,但逻辑上 rate limit 已通过
|
||||
// 验证码逻辑在 Mono.fromCallable 内部,阿里云不可用时会返回 false
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(success -> {
|
||||
// 阿里云不可用时会返回 false
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("获取验证码 - 从Redis获取成功")
|
||||
void testGetVerificationCodeFound() {
|
||||
String phone = "13812345678";
|
||||
String cacheKey = RedisKeyConstants.SMS_CODE + phone;
|
||||
|
||||
when(redisUtil.get(eq(cacheKey), eq(String.class)))
|
||||
.thenReturn(Mono.just("654321"));
|
||||
|
||||
Mono<String> result = smsService.getVerificationCode(phone);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNext("654321")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("获取验证码 - Redis中不存在")
|
||||
void testGetVerificationCodeNotFound() {
|
||||
String phone = "13800000000";
|
||||
String cacheKey = RedisKeyConstants.SMS_CODE + phone;
|
||||
|
||||
when(redisUtil.get(eq(cacheKey), eq(String.class)))
|
||||
.thenReturn(Mono.empty());
|
||||
|
||||
Mono<String> result = smsService.getVerificationCode(phone);
|
||||
|
||||
StepVerifier.create(result)
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("短信配置属性验证")
|
||||
void testSmsProperties() {
|
||||
when(smsProperties.getSignName()).thenReturn("测试签名");
|
||||
when(smsProperties.getTemplateCode()).thenReturn("SMS_001");
|
||||
when(smsProperties.getCodeLength()).thenReturn(6);
|
||||
when(smsProperties.getCodeExpireSeconds()).thenReturn(300L);
|
||||
|
||||
assert "测试签名".equals(smsProperties.getSignName());
|
||||
assert "SMS_001".equals(smsProperties.getTemplateCode());
|
||||
assert smsProperties.getCodeLength() == 6;
|
||||
assert smsProperties.getCodeExpireSeconds() == 300L;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user