Your Name | 292c25d | 2025-05-25 01:21:44 +0800 | [diff] [blame] | 1 | package edu.bjtu.groupone.backend; |
| 2 | |
| 3 | import edu.bjtu.groupone.backend.mapper.UserMapper; |
| 4 | import edu.bjtu.groupone.backend.utils.EmailUtil; |
| 5 | import edu.bjtu.groupone.backend.service.impl.UserServImpl; |
22301014 | f3cf5d5 | 2025-05-29 16:19:04 +0800 | [diff] [blame] | 6 | import edu.bjtu.groupone.backend.domain.entity.User; |
Your Name | 292c25d | 2025-05-25 01:21:44 +0800 | [diff] [blame] | 7 | import org.junit.jupiter.api.BeforeEach; |
| 8 | import org.junit.jupiter.api.Test; |
| 9 | import org.junit.jupiter.api.extension.ExtendWith; |
| 10 | import org.mockito.InjectMocks; |
| 11 | import org.mockito.Mock; |
| 12 | import org.mockito.junit.jupiter.MockitoExtension; |
| 13 | |
| 14 | import java.lang.reflect.Field; |
| 15 | |
| 16 | import static org.assertj.core.api.Assertions.*; |
| 17 | import static org.mockito.Mockito.*; |
| 18 | |
| 19 | /** |
| 20 | * 单元测试 UserServImpl 的核心逻辑:登录、发/验注册码、发/验重置码、重置密码。 |
| 21 | */ |
| 22 | @ExtendWith(MockitoExtension.class) |
| 23 | public class UserServImplTest { |
| 24 | |
| 25 | @Mock |
| 26 | private UserMapper userMapper; |
| 27 | |
| 28 | @Mock |
| 29 | private EmailUtil emailUtil; |
| 30 | |
| 31 | @InjectMocks |
| 32 | private UserServImpl userService; |
| 33 | |
| 34 | @BeforeEach |
| 35 | void clearCaches() throws Exception { |
| 36 | clearMap("emailCodes"); |
| 37 | clearMap("resetCodes"); |
| 38 | } |
| 39 | |
| 40 | @Test |
| 41 | public void login_shouldReturnUser_whenCredentialsMatch() { |
| 42 | User in = new User(); |
| 43 | in.setEmail("a@b.com"); |
| 44 | in.setPassword("pwd"); |
| 45 | User out = new User(); |
| 46 | out.setUserId(1); |
| 47 | out.setUsername("alice"); |
| 48 | out.setEmail("a@b.com"); |
| 49 | when(userMapper.login(in)).thenReturn(out); |
| 50 | |
| 51 | User result = userService.login(in); |
| 52 | assertThat(result).isSameAs(out); |
| 53 | verify(userMapper, times(1)).login(in); |
| 54 | } |
| 55 | |
| 56 | @Test |
| 57 | public void sendVerification_and_verifyCode_workCorrectly() throws Exception { |
| 58 | String email = "test@x.com"; |
| 59 | userService.sendVerificationCode(email); |
| 60 | verify(emailUtil).sendVerificationEmail(eq(email), anyString()); |
| 61 | |
| 62 | String stored = readMap("emailCodes", email); |
| 63 | String code = stored.split("\\|")[0]; |
| 64 | assertThat(userService.verifyCode(email, code)).isTrue(); |
| 65 | assertThat(userService.verifyCode(email, "000000")).isFalse(); |
| 66 | |
| 67 | // 模拟过期 |
| 68 | patchExpiry("emailCodes", email, -1000L); |
| 69 | assertThat(userService.verifyCode(email, code)).isFalse(); |
| 70 | } |
| 71 | |
| 72 | @Test |
| 73 | public void sendResetCode_and_resetPassword_workCorrectly() throws Exception { |
| 74 | String email = "reset@x.com"; |
| 75 | when(userMapper.selectByEmail(email)).thenReturn(null); |
| 76 | assertThatThrownBy(() -> userService.sendResetCode(email)) |
| 77 | .isInstanceOf(IllegalArgumentException.class); |
| 78 | |
| 79 | User u = new User(); |
| 80 | u.setEmail(email); |
| 81 | when(userMapper.selectByEmail(email)).thenReturn(u); |
| 82 | |
| 83 | userService.sendResetCode(email); |
| 84 | verify(emailUtil).sendVerificationEmail(eq(email), anyString()); |
| 85 | String stored = readMap("resetCodes", email); |
| 86 | String code = stored.split("\\|")[0]; |
| 87 | |
| 88 | when(userMapper.updatePasswordByEmail(email, "newpwd")).thenReturn(1); |
| 89 | assertThat(userService.resetPassword(email, code, "newpwd")).isTrue(); |
| 90 | assertThat(userService.resetPassword(email, code, "abc")).isFalse(); |
| 91 | |
| 92 | userService.sendResetCode(email); |
| 93 | String stored2 = readMap("resetCodes", email); |
| 94 | String code2 = stored2.split("\\|")[0]; |
| 95 | patchExpiry("resetCodes", email, -2000L); |
| 96 | assertThat(userService.resetPassword(email, code2, "pw")).isFalse(); |
| 97 | } |
| 98 | |
| 99 | // --- 反射辅助方法 --- |
| 100 | @SuppressWarnings("unchecked") |
| 101 | private void clearMap(String fieldName) throws Exception { |
| 102 | Field f = UserServImpl.class.getDeclaredField(fieldName); |
| 103 | f.setAccessible(true); |
| 104 | ((java.util.Map<String, String>)f.get(userService)).clear(); |
| 105 | } |
| 106 | |
| 107 | @SuppressWarnings("unchecked") |
| 108 | private String readMap(String fieldName, String key) throws Exception { |
| 109 | Field f = UserServImpl.class.getDeclaredField(fieldName); |
| 110 | f.setAccessible(true); |
| 111 | return ((java.util.Map<String, String>)f.get(userService)).get(key); |
| 112 | } |
| 113 | |
| 114 | @SuppressWarnings("unchecked") |
| 115 | private void patchExpiry(String fieldName, String key, long offsetMs) throws Exception { |
| 116 | String combined = readMap(fieldName, key); |
| 117 | String code = combined.split("\\|")[0]; |
| 118 | long expire = System.currentTimeMillis() + offsetMs; |
| 119 | String updated = code + "|" + expire; |
| 120 | Field f = UserServImpl.class.getDeclaredField(fieldName); |
| 121 | f.setAccessible(true); |
| 122 | ((java.util.Map<String, String>)f.get(userService)).put(key, updated); |
| 123 | } |
| 124 | } |