package com.tcm.training.admin.member.service; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.tcm.training.admin.common.PageResponse; import com.tcm.training.admin.live.mapper.ClinicMapper; import com.tcm.training.admin.member.entity.AppUser; import com.tcm.training.admin.member.mapper.UserMapper; import com.tcm.training.admin.member.row.UserDetailRow; import com.tcm.training.admin.member.row.UserListRow; import com.tcm.training.admin.member.vo.UserDetailVO; import com.tcm.training.admin.member.vo.UserListItemVO; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import java.time.LocalDateTime; import java.util.Collections; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class UserAppServiceTest { @BeforeAll static void initLambdaCache() { MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), ""); TableInfoHelper.initTableInfo(assistant, AppUser.class); } @Mock private UserMapper userMapper; @Mock private ClinicMapper clinicMapper; @Mock private BCryptPasswordEncoder passwordEncoder; @InjectMocks private UserAppService userAppService; @Test void pageShouldMapMemberExpireAtForMemberUserQuery() { LocalDateTime memberExpireAt = LocalDateTime.of(2026, 6, 8, 3, 15); UserListRow row = new UserListRow(); row.setId(11L); row.setNickname("王美丽"); row.setPhone("14712346905"); row.setAvatar("https://cdn.test/avatar.png"); row.setIsMember(1); row.setMemberExpireAt(memberExpireAt); IPage pageResult = new Page(1, 10, 1); pageResult.setRecords(Collections.singletonList(row)); when(userMapper.selectUserPage( any(), eq("王美丽"), eq("14712346905"), isNull(), isNull(), isNull(), eq("ACTIVE"), isNull(), isNull(), isNull(), isNull() )).thenReturn(pageResult); PageResponse result = userAppService.page( 1, 10, " 王美丽 ", "14712346905", null, null, null, "active", null, null, null, null ); assertEquals(1, result.getList().size()); assertEquals(memberExpireAt, result.getList().get(0).getMemberExpireAt()); assertEquals(Boolean.TRUE, result.getList().get(0).getIsMember()); } @Test void pageShouldRejectInvalidMemberStatus() { IllegalArgumentException error = assertThrows( IllegalArgumentException.class, () -> userAppService.page( 1, 10, null, null, null, null, null, "INVALID", null, null, null, null ) ); assertEquals("会员状态筛选不合法", error.getMessage()); } @Test void unbindWechatShouldClearWechatFieldsWithExplicitNullUpdate() { AppUser user = new AppUser(); user.setId(12L); user.setDeleted(0); UserDetailRow detailRow = new UserDetailRow(); detailRow.setId(12L); detailRow.setNickname("张医生"); when(userMapper.selectOne(any())).thenReturn(user); when(userMapper.selectUserDetail(12L)).thenReturn(detailRow); UserDetailVO result = userAppService.unbindWechat(12L); ArgumentCaptor> wrapperCaptor = ArgumentCaptor.forClass(LambdaUpdateWrapper.class); verify(userMapper).update(isNull(), wrapperCaptor.capture()); verify(userMapper, never()).updateById(any(AppUser.class)); String sqlSet = wrapperCaptor.getValue().getSqlSet(); assertTrue(sqlSet.contains("wechat_openid")); assertTrue(sqlSet.contains("wechat_nickname")); assertTrue(sqlSet.contains("wechat_avatar")); assertTrue(sqlSet.contains("wechat_bound_at")); assertTrue(wrapperCaptor.getValue().getParamNameValuePairs().values().stream().allMatch(value -> value == null)); assertEquals(Long.valueOf(12L), result.getId()); } }