修复登录,注册的bug

This commit is contained in:
2025-08-09 01:22:54 +08:00
parent 927fab3bdd
commit 3daffdf323
6 changed files with 297 additions and 286 deletions

View File

@ -220,15 +220,26 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效"); ThrowUtils.throwIf(RegexUtils.isPhoneInvalid(phoneNumber), ErrorCode.PARAMS_ERROR, "手机号格式无效");
String userPassword = userInfoMiniPasswordLoginRequest.getUserPassword(); String userPassword = userInfoMiniPasswordLoginRequest.getUserPassword();
String userRole = userInfoMiniPasswordLoginRequest.getUserRole(); String userRole = userInfoMiniPasswordLoginRequest.getUserRole();
UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(userRole);
LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber); if (UserRoleEnum.USER.equals(userRoleEnum)) {
lambdaQueryWrapper.eq(UserInfo::getUserRole, userRole); lambdaQueryWrapper.eq(UserInfo::getUserRole, userRole);
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber);
UserInfo userInfo = this.getOne(lambdaQueryWrapper); UserInfo userInfo = this.getOne(lambdaQueryWrapper);
ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "手机号未注册"); ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "手机号未注册");
} else {
lambdaQueryWrapper.eq(UserInfo::getPhoneNumber, phoneNumber);
lambdaQueryWrapper.in(UserInfo::getUserRole, UserRoleEnum.STAFF.getValue(), UserRoleEnum.SUPERVISOR.getValue(), UserRoleEnum.MANAGER.getValue());
UserInfo userInfo = this.getOne(lambdaQueryWrapper);
ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "手机号未注册");
UserRoleEnum currentUserRoleEnum = UserRoleEnum.getEnumByValue(userInfo.getUserRole());
ThrowUtils.throwIf(!userRoleEnum.equals(currentUserRoleEnum), ErrorCode.OPERATION_ERROR, "该手机号为" + currentUserRoleEnum.getText() + "账号");
}
lambdaQueryWrapper.eq(UserInfo::getUserPassword, userPassword); lambdaQueryWrapper.eq(UserInfo::getUserPassword, userPassword);
userInfo = this.getOne(lambdaQueryWrapper); UserInfo userInfo = this.getOne(lambdaQueryWrapper);
ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "密码不正确"); ThrowUtils.throwIf(userInfo == null, ErrorCode.OPERATION_ERROR, "密码不正确");
Map<String, String> payload = new HashMap<>(); Map<String, String> payload = new HashMap<>();
payload.put("userAccount", phoneNumber); payload.put("userAccount", phoneNumber);
payload.put("userPassword", userPassword); payload.put("userPassword", userPassword);

View File

@ -33,8 +33,8 @@ public class SendSmsUtil {
// 设置请求参数 // 设置请求参数
List<NameValuePair> data = new ArrayList<>(); List<NameValuePair> data = new ArrayList<>();
data.add(new BasicNameValuePair("account", "C08121984")); data.add(new BasicNameValuePair("account", "C55991947"));
data.add(new BasicNameValuePair("password", "84a27a879413ec629bf26c5d84a25271")); data.add(new BasicNameValuePair("password", "d3979496a8d9c7e9a322804b7ed187e2"));
data.add(new BasicNameValuePair("mobile", phoneNumber)); data.add(new BasicNameValuePair("mobile", phoneNumber));
data.add(new BasicNameValuePair("content", content)); data.add(new BasicNameValuePair("content", content));

View File

@ -1,4 +1,4 @@
spring: spring:
profiles: profiles:
active: caozhe active: test

View File

@ -1,79 +1,79 @@
package com.greenorange.promotion.junit; //package com.greenorange.promotion.junit;
//
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; //import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.greenorange.promotion.model.dto.CommonBatchRequest; //import com.greenorange.promotion.model.dto.CommonBatchRequest;
import com.greenorange.promotion.model.entity.PromoCode; //import com.greenorange.promotion.model.entity.PromoCode;
import com.greenorange.promotion.service.project.impl.PromoCodeServiceImpl; //import com.greenorange.promotion.service.project.impl.PromoCodeServiceImpl;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; //import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; //import org.mockito.InjectMocks;
import org.mockito.Spy; //import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension; //import org.mockito.junit.jupiter.MockitoExtension;
//
import java.util.Arrays; //import java.util.Arrays;
import java.util.Collections; //import java.util.Collections;
import java.util.List; //import java.util.List;
//
import static org.junit.jupiter.api.Assertions.assertThrows; //import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; //import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*; //import static org.mockito.Mockito.*;
//
@ExtendWith(MockitoExtension.class) //@ExtendWith(MockitoExtension.class)
class PromoCodeServiceImplTest { //class PromoCodeServiceImplTest {
//
@Spy // @Spy
@InjectMocks // @InjectMocks
private PromoCodeServiceImpl service; // private PromoCodeServiceImpl service;
// Spy + InjectMocks使用真实的 PromoCodeServiceImpl但可以 stub 它的 list(...) 和 removeByIds(...) // // Spy + InjectMocks使用真实的 PromoCodeServiceImpl但可以 stub 它的 list(...) 和 removeByIds(...)
//
/** // /**
* 当存在状态为“占用”的推广码时,应抛出异常并且不执行删除 // * 当存在状态为“占用”的推广码时,应抛出异常并且不执行删除
*/ // */
@Test // @Test
void delBatchPromoCode_whenCodesInUse_shouldThrow() { // void delBatchPromoCode_whenCodesInUse_shouldThrow() {
// Arrange // // Arrange
List<Long> ids = Arrays.asList(1L, 2L, 3L); // List<Long> ids = Arrays.asList(1L, 2L, 3L);
CommonBatchRequest req = new CommonBatchRequest(); // CommonBatchRequest req = new CommonBatchRequest();
req.setIds(ids); // req.setIds(ids);
//
// 模拟 list(...) 返回一个非空列表,表示有正在使用的推广码 // // 模拟 list(...) 返回一个非空列表,表示有正在使用的推广码
PromoCode inUse = new PromoCode(); // PromoCode inUse = new PromoCode();
inUse.setId(2L); // inUse.setId(2L);
inUse.setPromoCodeStatus(true); // inUse.setPromoCodeStatus(true);
doReturn(Collections.singletonList(inUse)) // doReturn(Collections.singletonList(inUse))
.when(service).list(any(LambdaQueryWrapper.class)); // .when(service).list(any(LambdaQueryWrapper.class));
//
// Act & Assert // // Act & Assert
RuntimeException ex = assertThrows(RuntimeException.class, // RuntimeException ex = assertThrows(RuntimeException.class,
() -> service.delBatchPromoCode(req)); // () -> service.delBatchPromoCode(req));
assertTrue(ex.getMessage().contains("当前推广码正在使用中")); // assertTrue(ex.getMessage().contains("当前推广码正在使用中"));
//
// 验证 removeByIds(...) 从未被调用 // // 验证 removeByIds(...) 从未被调用
verify(service, never()).removeByIds(anyList()); // verify(service, never()).removeByIds(anyList());
} // }
//
/** // /**
* 当所有推广码都未被占用时,应正常调用 removeByIds 删除 // * 当所有推广码都未被占用时,应正常调用 removeByIds 删除
*/ // */
@Test // @Test
void delBatchPromoCode_whenNoCodesInUse_shouldRemove() { // void delBatchPromoCode_whenNoCodesInUse_shouldRemove() {
// Arrange // // Arrange
List<Long> ids = Arrays.asList(4L, 5L); // List<Long> ids = Arrays.asList(4L, 5L);
CommonBatchRequest req = new CommonBatchRequest(); // CommonBatchRequest req = new CommonBatchRequest();
req.setIds(ids); // req.setIds(ids);
//
// 模拟 list(...) 返回空列表,表示无任何占用的推广码 // // 模拟 list(...) 返回空列表,表示无任何占用的推广码
doReturn(Collections.emptyList()) // doReturn(Collections.emptyList())
.when(service).list(any(LambdaQueryWrapper.class)); // .when(service).list(any(LambdaQueryWrapper.class));
//
// 模拟 removeByIds(...) 返回 true表示删除成功 // // 模拟 removeByIds(...) 返回 true表示删除成功
doReturn(true).when(service).removeByIds(ids); // doReturn(true).when(service).removeByIds(ids);
//
// Act // // Act
service.delBatchPromoCode(req); // service.delBatchPromoCode(req);
//
// Assert // // Assert
// 验证 removeByIds(...) 被调用一次,且参数正是传入的 ids // // 验证 removeByIds(...) 被调用一次,且参数正是传入的 ids
verify(service, times(1)).removeByIds(ids); // verify(service, times(1)).removeByIds(ids);
} // }
} //}

View File

@ -1,96 +1,96 @@
package com.greenorange.promotion.junit; //package com.greenorange.promotion.junit;
//
import com.greenorange.promotion.model.dto.userAccount.UserAccountUpdateRequest; //import com.greenorange.promotion.model.dto.userAccount.UserAccountUpdateRequest;
import com.greenorange.promotion.model.entity.UserAccount; //import com.greenorange.promotion.model.entity.UserAccount;
import com.greenorange.promotion.service.common.CommonService; //import com.greenorange.promotion.service.common.CommonService;
import com.greenorange.promotion.service.settle.impl.UserAccountServiceImpl; //import com.greenorange.promotion.service.settle.impl.UserAccountServiceImpl;
import jakarta.servlet.http.HttpServletRequest; //import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; //import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; //import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks; //import org.mockito.InjectMocks;
import org.mockito.Mock; //import org.mockito.Mock;
import org.mockito.Spy; //import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension; //import org.mockito.junit.jupiter.MockitoExtension;
//
import static org.junit.jupiter.api.Assertions.assertEquals; //import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame; //import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.*; //import static org.mockito.Mockito.*;
//
@ExtendWith(MockitoExtension.class) //@ExtendWith(MockitoExtension.class)
class UserAccountServiceImplTest { //class UserAccountServiceImplTest {
//
@Spy // @Spy
@InjectMocks // @InjectMocks
private UserAccountServiceImpl userAccountService; // private UserAccountServiceImpl userAccountService;
// Spy + InjectMocks用真实的 serviceImpl但可以对它的方法做部分 stub // // Spy + InjectMocks用真实的 serviceImpl但可以对它的方法做部分 stub
//
@Mock // @Mock
private CommonService commonService; // private CommonService commonService;
// Mock CommonService用于模拟 copyProperties // // Mock CommonService用于模拟 copyProperties
//
@Mock // @Mock
private HttpServletRequest request; // private HttpServletRequest request;
// Mock HttpServletRequest用于模拟获取 userId // // Mock HttpServletRequest用于模拟获取 userId
//
@Test // @Test
void updateUserAccount_shouldCopyProperties_setUserId_andUpdateById() { // void updateUserAccount_shouldCopyProperties_setUserId_andUpdateById() {
// --- Arrange 准备阶段 --- // // --- Arrange 准备阶段 ---
Long userId = 456L; // Long userId = 456L;
// 模拟从 request 中拿到当前登录用户 ID // // 模拟从 request 中拿到当前登录用户 ID
when(request.getAttribute("userId")).thenReturn(userId); // when(request.getAttribute("userId")).thenReturn(userId);
//
// 构造更新请求 DTO并设置要更新的账户 ID // // 构造更新请求 DTO并设置要更新的账户 ID
UserAccountUpdateRequest req = new UserAccountUpdateRequest(); // UserAccountUpdateRequest req = new UserAccountUpdateRequest();
req.setId(99L); // req.setId(99L);
req.setCardHolder("李四"); // req.setCardHolder("李四");
req.setIdCardNumber("110101199002022345"); // req.setIdCardNumber("110101199002022345");
req.setPhoneNumber("15900001111"); // req.setPhoneNumber("15900001111");
req.setBankCardNumber("6222020202020202"); // req.setBankCardNumber("6222020202020202");
req.setOpenBank("中国农业银行"); // req.setOpenBank("中国农业银行");
//
// 准备一个空实体,模拟 commonService.copyProperties 拷贝结果 // // 准备一个空实体,模拟 commonService.copyProperties 拷贝结果
UserAccount stubEntity = new UserAccount(); // UserAccount stubEntity = new UserAccount();
// 假设 copyProperties 会拷贝所有字段,包括 id // // 假设 copyProperties 会拷贝所有字段,包括 id
stubEntity.setId(req.getId()); // stubEntity.setId(req.getId());
stubEntity.setCardHolder(req.getCardHolder()); // stubEntity.setCardHolder(req.getCardHolder());
stubEntity.setIdCardNumber(req.getIdCardNumber()); // stubEntity.setIdCardNumber(req.getIdCardNumber());
stubEntity.setPhoneNumber(req.getPhoneNumber()); // stubEntity.setPhoneNumber(req.getPhoneNumber());
stubEntity.setBankCardNumber(req.getBankCardNumber()); // stubEntity.setBankCardNumber(req.getBankCardNumber());
stubEntity.setOpenBank(req.getOpenBank()); // stubEntity.setOpenBank(req.getOpenBank());
// stub copyProperties 返回我们准备的 stubEntity // // stub copyProperties 返回我们准备的 stubEntity
when(commonService.copyProperties(req, UserAccount.class)) // when(commonService.copyProperties(req, UserAccount.class))
.thenReturn(stubEntity); // .thenReturn(stubEntity);
//
// 对 Spy 的 updateById(...) 方法做 stub避免走到 MyBatis-Plus 真逻辑 // // 对 Spy 的 updateById(...) 方法做 stub避免走到 MyBatis-Plus 真逻辑
doReturn(true).when(userAccountService).updateById(any(UserAccount.class)); // doReturn(true).when(userAccountService).updateById(any(UserAccount.class));
//
// --- Act 执行阶段 --- // // --- Act 执行阶段 ---
userAccountService.updateUserAccount(req, request); // userAccountService.updateUserAccount(req, request);
// 方法内部执行顺序: // // 方法内部执行顺序:
// 1. 取 request.getAttribute("userId") -> 456L // // 1. 取 request.getAttribute("userId") -> 456L
// 2. commonService.copyProperties(req, UserAccount.class) -> stubEntity // // 2. commonService.copyProperties(req, UserAccount.class) -> stubEntity
// 3. stubEntity.setUserId(456L) // // 3. stubEntity.setUserId(456L)
// 4. 调用 updateById(stubEntity) // // 4. 调用 updateById(stubEntity)
//
// --- Assert 验证阶段 --- // // --- Assert 验证阶段 ---
// 捕获 updateById 调用时传入的参数 // // 捕获 updateById 调用时传入的参数
ArgumentCaptor<UserAccount> captor = ArgumentCaptor.forClass(UserAccount.class); // ArgumentCaptor<UserAccount> captor = ArgumentCaptor.forClass(UserAccount.class);
verify(userAccountService).updateById(captor.capture()); // verify(userAccountService).updateById(captor.capture());
UserAccount updated = captor.getValue(); // UserAccount updated = captor.getValue();
//
// 验证传给 updateById 的正是 stubEntity 对象 // // 验证传给 updateById 的正是 stubEntity 对象
assertSame(stubEntity, updated, "应该传入同一个 stubEntity 实例"); // assertSame(stubEntity, updated, "应该传入同一个 stubEntity 实例");
//
// 验证 userId 已正确赋值 // // 验证 userId 已正确赋值
assertEquals(userId, updated.getUserId(), "userId 应该从 request 中取出并赋值"); // assertEquals(userId, updated.getUserId(), "userId 应该从 request 中取出并赋值");
//
// 验证其他字段都被 copyProperties 拷贝过来,包括账户 ID // // 验证其他字段都被 copyProperties 拷贝过来,包括账户 ID
assertEquals(req.getId(), updated.getId(), "账户 ID 应保持一致"); // assertEquals(req.getId(), updated.getId(), "账户 ID 应保持一致");
assertEquals("李四", updated.getCardHolder(), "持卡人应一致"); // assertEquals("李四", updated.getCardHolder(), "持卡人应一致");
assertEquals("110101199002022345", updated.getIdCardNumber(), "身份证号应一致"); // assertEquals("110101199002022345", updated.getIdCardNumber(), "身份证号应一致");
assertEquals("15900001111", updated.getPhoneNumber(), "手机号应一致"); // assertEquals("15900001111", updated.getPhoneNumber(), "手机号应一致");
assertEquals("6222020202020202", updated.getBankCardNumber(),"银行卡号应一致"); // assertEquals("6222020202020202", updated.getBankCardNumber(),"银行卡号应一致");
assertEquals("中国农业银行", updated.getOpenBank(), "开户银行应一致"); // assertEquals("中国农业银行", updated.getOpenBank(), "开户银行应一致");
} // }
} //}

View File

@ -1,103 +1,103 @@
package com.greenorange.promotion.junit; //package com.greenorange.promotion.junit;
//
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; //import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.greenorange.promotion.model.dto.userInfo.UserInfoMiniPasswordLoginRequest; //import com.greenorange.promotion.model.dto.userInfo.UserInfoMiniPasswordLoginRequest;
import com.greenorange.promotion.model.entity.UserInfo; //import com.greenorange.promotion.model.entity.UserInfo;
import com.greenorange.promotion.service.userInfo.impl.UserInfoServiceImpl; //import com.greenorange.promotion.service.userInfo.impl.UserInfoServiceImpl;
import com.greenorange.promotion.utils.JWTUtils; //import com.greenorange.promotion.utils.JWTUtils;
import org.junit.jupiter.api.BeforeEach; //import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; //import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; //import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*; //import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension; //import org.mockito.junit.jupiter.MockitoExtension;
//
import java.util.Map; //import java.util.Map;
//
import static org.junit.jupiter.api.Assertions.*; //import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any; //import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; //import static org.mockito.Mockito.*;
//
@ExtendWith(MockitoExtension.class) //@ExtendWith(MockitoExtension.class)
class UserInfoServiceImplTest { //class UserInfoServiceImplTest {
//
@Spy // @Spy
@InjectMocks // @InjectMocks
private UserInfoServiceImpl userService; // 真实的 ServiceImpl部分方法用 spy // private UserInfoServiceImpl userService; // 真实的 ServiceImpl部分方法用 spy
//
@Mock // @Mock
private JWTUtils jwtUtils; // 用来生成 token 的工具 // private JWTUtils jwtUtils; // 用来生成 token 的工具
//
@BeforeEach // @BeforeEach
void setUp() { // void setUp() {
// MockitoAnnotations.openMocks(this); // @ExtendWith 已自动初始化 // // MockitoAnnotations.openMocks(this); // @ExtendWith 已自动初始化
} // }
//
private UserInfoMiniPasswordLoginRequest buildRequest(String phone, String pwd) { // private UserInfoMiniPasswordLoginRequest buildRequest(String phone, String pwd) {
UserInfoMiniPasswordLoginRequest req = new UserInfoMiniPasswordLoginRequest(); // UserInfoMiniPasswordLoginRequest req = new UserInfoMiniPasswordLoginRequest();
req.setPhoneNumber(phone); // req.setPhoneNumber(phone);
req.setUserPassword(pwd); // req.setUserPassword(pwd);
return req; // return req;
} // }
//
/** 1. 手机号格式无效,应直接抛参数错误 */ // /** 1. 手机号格式无效,应直接抛参数错误 */
@Test // @Test
void givenInvalidPhone_whenLoginByPwd_thenThrow() { // void givenInvalidPhone_whenLoginByPwd_thenThrow() {
UserInfoMiniPasswordLoginRequest req = buildRequest("not-a-phone", "whatever"); // UserInfoMiniPasswordLoginRequest req = buildRequest("not-a-phone", "whatever");
assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req)); // assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req));
} // }
//
/** 2. 手机号未注册,应抛操作错误 */ // /** 2. 手机号未注册,应抛操作错误 */
@Test // @Test
void givenUnregisteredPhone_whenLoginByPwd_thenThrow() { // void givenUnregisteredPhone_whenLoginByPwd_thenThrow() {
// stub 第一次 getOne(...) 返回 null // // stub 第一次 getOne(...) 返回 null
doReturn(null) // doReturn(null)
.when(userService).getOne(any(LambdaQueryWrapper.class)); // .when(userService).getOne(any(LambdaQueryWrapper.class));
//
UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "pwd"); // UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "pwd");
assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req)); // assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req));
} // }
//
/** 3. 密码不正确,应抛操作错误 */ // /** 3. 密码不正确,应抛操作错误 */
@Test // @Test
void givenWrongPassword_whenLoginByPwd_thenThrow() { // void givenWrongPassword_whenLoginByPwd_thenThrow() {
UserInfo dummy = new UserInfo(); // UserInfo dummy = new UserInfo();
dummy.setPhoneNumber("13812345678"); // dummy.setPhoneNumber("13812345678");
dummy.setUserPassword("rightPwd"); // dummy.setUserPassword("rightPwd");
//
// stub 第一次 getOne(...) 返回非 null手机号存在 // // stub 第一次 getOne(...) 返回非 null手机号存在
// stub 第二次 getOne(...) 返回 null密码校验失败 // // stub 第二次 getOne(...) 返回 null密码校验失败
doReturn(dummy, null) // doReturn(dummy, null)
.when(userService).getOne(any(LambdaQueryWrapper.class)); // .when(userService).getOne(any(LambdaQueryWrapper.class));
//
UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "wrongPwd"); // UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "wrongPwd");
assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req)); // assertThrows(RuntimeException.class, () -> userService.userInfoMiniLoginByPwd(req));
} // }
//
/** 4. 成功场景:正确手机号 + 密码,返回 token并验证 jwtUtils 调用 */ // /** 4. 成功场景:正确手机号 + 密码,返回 token并验证 jwtUtils 调用 */
@Test // @Test
void givenValidCredentials_whenLoginByPwd_thenReturnToken() { // void givenValidCredentials_whenLoginByPwd_thenReturnToken() {
UserInfo dummy = new UserInfo(); // UserInfo dummy = new UserInfo();
dummy.setPhoneNumber("13812345678"); // dummy.setPhoneNumber("13812345678");
dummy.setUserPassword("rightPwd"); // dummy.setUserPassword("rightPwd");
//
// stub getOne(...) 两次都返回同一个 dummy表示手机号存在且密码正确 // // stub getOne(...) 两次都返回同一个 dummy表示手机号存在且密码正确
doReturn(dummy, dummy) // doReturn(dummy, dummy)
.when(userService).getOne(any(LambdaQueryWrapper.class)); // .when(userService).getOne(any(LambdaQueryWrapper.class));
//
// stub jwtUtils.generateToken(...) // // stub jwtUtils.generateToken(...)
String expectedToken = "jwt-token-xyz"; // String expectedToken = "jwt-token-xyz";
when(jwtUtils.generateToken(anyMap())).thenReturn(expectedToken); // when(jwtUtils.generateToken(anyMap())).thenReturn(expectedToken);
//
UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "rightPwd"); // UserInfoMiniPasswordLoginRequest req = buildRequest("13812345678", "rightPwd");
String token = userService.userInfoMiniLoginByPwd(req); // String token = userService.userInfoMiniLoginByPwd(req);
//
assertEquals(expectedToken, token); // assertEquals(expectedToken, token);
//
// 验证 payload 内容正确 // // 验证 payload 内容正确
ArgumentCaptor<Map<String, String>> captor = ArgumentCaptor.forClass(Map.class); // ArgumentCaptor<Map<String, String>> captor = ArgumentCaptor.forClass(Map.class);
verify(jwtUtils, times(1)).generateToken(captor.capture()); // verify(jwtUtils, times(1)).generateToken(captor.capture());
Map<String, String> payload = captor.getValue(); // Map<String, String> payload = captor.getValue();
assertEquals("13812345678", payload.get("userAccount")); // assertEquals("13812345678", payload.get("userAccount"));
assertEquals("rightPwd", payload.get("userPassword")); // assertEquals("rightPwd", payload.get("userPassword"));
} // }
} //}