hejianhao
2026-08-28 16a57a8fc6868cea9171a1119698572407a2fc03
tcm-training-admin-backend/src/test/java/com/tcm/training/admin/app/settings/service/AppSettingsServiceTest.java
@@ -2,12 +2,13 @@
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import cn.dev33.satoken.stp.SaTokenInfo;
import com.tcm.training.admin.app.auth.service.AppAuthSessionService;
import com.tcm.training.admin.app.auth.vo.AppLoginResponse;
import com.tcm.training.admin.app.auth.service.AppSmsCodeService;
import com.tcm.training.admin.app.auth.service.AppWechatAuthClient;
import com.tcm.training.admin.app.settings.dto.AppSettingsPhoneBindRequest;
import com.tcm.training.admin.app.settings.mapper.AppUserNotificationSettingMapper;
import com.tcm.training.admin.app.settings.vo.AppSettingsProfileVO;
import com.tcm.training.admin.app.share.service.AppShareService;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.mapper.UserMapper;
@@ -28,6 +29,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -103,12 +105,15 @@
        when(userMapper.selectById(1L)).thenReturn(currentUser);
        when(userMapper.selectOne(any())).thenReturn(null);
        doNothing().when(appSmsCodeService).validatePhoneChangeCode("13800138000", "123456");
        when(appAuthSessionService.getTokenInfo()).thenReturn(buildToken("bind-token"));
        AppSettingsProfileVO response = appSettingsService.bindPhone(request);
        AppLoginResponse response = appSettingsService.bindPhone(request);
        verify(userMapper).updateById(appUserCaptor.capture());
        verify(appAuthSessionService).login(1L);
        assertEquals("13800138000", appUserCaptor.getValue().getPhone());
        assertEquals("13800138000", response.getPhone());
        assertEquals("13800138000", response.getUser().getPhone());
        assertEquals("bind-token", response.getToken());
    }
    /**
@@ -132,10 +137,141 @@
    }
    /**
     * 目标手机号被其他有效用户占用时不允许绑定。
     * 微信临时账号绑定已注册但未绑定微信的手机号时,应合并到手机号账号。
     */
    @Test
    void bindPhoneShouldRejectOccupiedPhone() {
    void bindPhoneShouldMergeWechatUserIntoExistingPhoneUser() {
        AppSettingsPhoneBindRequest request = new AppSettingsPhoneBindRequest();
        request.setNewPhone("13800138000");
        request.setCode("123456");
        AppUser currentUser = buildEnabledUser(null);
        currentUser.setWechatOpenid("wx-openid");
        currentUser.setNickname(null);
        currentUser.setWechatNickname("微信昵称");
        AppUser occupiedUser = buildEnabledUser("13800138000");
        occupiedUser.setId(2L);
        occupiedUser.setNickname(null);
        when(appAuthSessionService.requireLoginUserId()).thenReturn(1L);
        when(userMapper.selectById(1L)).thenReturn(currentUser);
        when(userMapper.selectOne(any())).thenReturn(occupiedUser);
        doNothing().when(appSmsCodeService).validatePhoneChangeCode("13800138000", "123456");
        when(appAuthSessionService.getTokenInfo()).thenReturn(buildToken("merged-token"));
        AppLoginResponse response = appSettingsService.bindPhone(request);
        verify(userMapper, times(2)).updateById(appUserCaptor.capture());
        AppUser mergedUser = appUserCaptor.getAllValues().get(0);
        AppUser deletedTemporaryUser = appUserCaptor.getAllValues().get(1);
        verify(appAuthSessionService).login(2L);
        assertEquals("wx-openid", mergedUser.getWechatOpenid());
        assertEquals("微信昵称", mergedUser.getNickname());
        assertEquals(Integer.valueOf(1), deletedTemporaryUser.getDeleted());
        assertEquals(Long.valueOf(2L), response.getUser().getId());
        assertEquals("merged-token", response.getToken());
    }
    /**
     * 微信临时账号绑定已绑定微信的手机号时,应直接覆盖目标账号微信票据。
     */
    @Test
    void bindPhoneShouldOverwriteWechatBindingWhenPhoneUserAlreadyBoundWechat() {
        AppSettingsPhoneBindRequest request = new AppSettingsPhoneBindRequest();
        request.setNewPhone("13800138000");
        request.setCode("123456");
        AppUser currentUser = buildEnabledUser(null);
        currentUser.setWechatOpenid("wx-openid");
        currentUser.setWechatNickname("新微信昵称");
        AppUser occupiedUser = buildEnabledUser("13800138000");
        occupiedUser.setId(2L);
        occupiedUser.setWechatOpenid("other-wx-openid");
        when(appAuthSessionService.requireLoginUserId()).thenReturn(1L);
        when(userMapper.selectById(1L)).thenReturn(currentUser);
        when(userMapper.selectOne(any())).thenReturn(occupiedUser);
        doNothing().when(appSmsCodeService).validatePhoneChangeCode("13800138000", "123456");
        when(appAuthSessionService.getTokenInfo()).thenReturn(buildToken("wechat-overwrite-token"));
        AppLoginResponse response = appSettingsService.bindPhone(request);
        verify(userMapper, times(2)).updateById(appUserCaptor.capture());
        AppUser mergedUser = appUserCaptor.getAllValues().get(0);
        AppUser deletedTemporaryUser = appUserCaptor.getAllValues().get(1);
        verify(appAuthSessionService).login(2L);
        assertEquals("wx-openid", mergedUser.getWechatOpenid());
        assertEquals("新微信昵称", mergedUser.getWechatNickname());
        assertEquals(Integer.valueOf(1), deletedTemporaryUser.getDeleted());
        assertEquals(Long.valueOf(2L), response.getUser().getId());
    }
    /**
     * 苹果临时账号绑定已注册但未绑定苹果的手机号时,应合并到手机号账号。
     */
    @Test
    void bindPhoneShouldMergeAppleUserIntoExistingPhoneUser() {
        AppSettingsPhoneBindRequest request = new AppSettingsPhoneBindRequest();
        request.setNewPhone("13800138000");
        request.setCode("123456");
        AppUser currentUser = buildEnabledUser(null);
        currentUser.setAppleIdentitySubject("apple-subject");
        currentUser.setAppleUserIdentifier("apple-user");
        AppUser occupiedUser = buildEnabledUser("13800138000");
        occupiedUser.setId(2L);
        when(appAuthSessionService.requireLoginUserId()).thenReturn(1L);
        when(userMapper.selectById(1L)).thenReturn(currentUser);
        when(userMapper.selectOne(any())).thenReturn(occupiedUser);
        doNothing().when(appSmsCodeService).validatePhoneChangeCode("13800138000", "123456");
        when(appAuthSessionService.getTokenInfo()).thenReturn(buildToken("apple-merged-token"));
        AppLoginResponse response = appSettingsService.bindPhone(request);
        verify(userMapper, times(2)).updateById(appUserCaptor.capture());
        AppUser mergedUser = appUserCaptor.getAllValues().get(0);
        verify(appAuthSessionService).login(2L);
        assertEquals("apple-subject", mergedUser.getAppleIdentitySubject());
        assertEquals("apple-user", mergedUser.getAppleUserIdentifier());
        assertEquals(Long.valueOf(2L), response.getUser().getId());
    }
    /**
     * 苹果临时账号绑定已绑定苹果的手机号时,应直接覆盖目标账号苹果票据。
     */
    @Test
    void bindPhoneShouldOverwriteAppleBindingWhenPhoneUserAlreadyBoundApple() {
        AppSettingsPhoneBindRequest request = new AppSettingsPhoneBindRequest();
        request.setNewPhone("13800138000");
        request.setCode("123456");
        AppUser currentUser = buildEnabledUser(null);
        currentUser.setAppleIdentitySubject("apple-subject");
        currentUser.setAppleUserIdentifier("apple-user");
        AppUser occupiedUser = buildEnabledUser("13800138000");
        occupiedUser.setId(2L);
        occupiedUser.setAppleIdentitySubject("other-apple-subject");
        when(appAuthSessionService.requireLoginUserId()).thenReturn(1L);
        when(userMapper.selectById(1L)).thenReturn(currentUser);
        when(userMapper.selectOne(any())).thenReturn(occupiedUser);
        doNothing().when(appSmsCodeService).validatePhoneChangeCode("13800138000", "123456");
        when(appAuthSessionService.getTokenInfo()).thenReturn(buildToken("apple-overwrite-token"));
        AppLoginResponse response = appSettingsService.bindPhone(request);
        verify(userMapper, times(2)).updateById(appUserCaptor.capture());
        AppUser mergedUser = appUserCaptor.getAllValues().get(0);
        AppUser deletedTemporaryUser = appUserCaptor.getAllValues().get(1);
        verify(appAuthSessionService).login(2L);
        assertEquals("apple-subject", mergedUser.getAppleIdentitySubject());
        assertEquals("apple-user", mergedUser.getAppleUserIdentifier());
        assertEquals(Integer.valueOf(1), deletedTemporaryUser.getDeleted());
        assertEquals(Long.valueOf(2L), response.getUser().getId());
    }
    /**
     * 非第三方临时账号绑定已注册手机号时仍按占用处理。
     */
    @Test
    void bindPhoneShouldRejectOccupiedPhoneWithoutThirdPartyBinding() {
        AppSettingsPhoneBindRequest request = new AppSettingsPhoneBindRequest();
        request.setNewPhone("13800138000");
        request.setCode("123456");
@@ -177,6 +313,16 @@
    }
    /**
     * 构造测试登录态。
     */
    private SaTokenInfo buildToken(String tokenValue) {
        SaTokenInfo tokenInfo = new SaTokenInfo();
        tokenInfo.setTokenValue(tokenValue);
        tokenInfo.setTokenTimeout(7200L);
        return tokenInfo;
    }
    /**
     * 构造启用状态 APP 用户。
     */
    private AppUser buildEnabledUser(String phone) {