Commit f640b67159208a0c6827574b7002e683cb0eb9b6
1 parent
f2136c43
🐛 fix(im):codex 评审修复 IM 单测契约
- ImPrivateMessageServiceImplTest 用 getFriendState 替换已删除的 isFriend mock;返回 ImFriendStateEnum.FRIEND / NONE - ImFriendServiceImplTest 删 stale 测试(isFriend / addFriend / deleteFriend 二参版本均已不存在);addFriend0 测试参数补齐 null displayName / addSource 凑齐 4 参签名 - 修复后 mvn -pl yudao-module-im test-compile 通过 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Showing
2 changed files
with
9 additions
and
87 deletions
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/friend/ImFriendServiceImplTest.java
| 1 | package cn.iocoder.yudao.module.im.service.friend; | 1 | package cn.iocoder.yudao.module.im.service.friend; |
| 2 | 2 | ||
| 3 | -import cn.hutool.extra.spring.SpringUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 4 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| @@ -15,21 +14,16 @@ import org.junit.jupiter.api.Test; | @@ -15,21 +14,16 @@ import org.junit.jupiter.api.Test; | ||
| 15 | import org.mockito.ArgumentCaptor; | 14 | import org.mockito.ArgumentCaptor; |
| 16 | import org.mockito.InjectMocks; | 15 | import org.mockito.InjectMocks; |
| 17 | import org.mockito.Mock; | 16 | import org.mockito.Mock; |
| 18 | -import org.mockito.MockedStatic; | ||
| 19 | import org.springframework.dao.DuplicateKeyException; | 17 | import org.springframework.dao.DuplicateKeyException; |
| 20 | 18 | ||
| 21 | import java.time.LocalDateTime; | 19 | import java.time.LocalDateTime; |
| 22 | import java.util.List; | 20 | import java.util.List; |
| 23 | 21 | ||
| 24 | -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_ADD_SELF; | ||
| 25 | import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND; | 22 | import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND; |
| 26 | import static org.junit.jupiter.api.Assertions.*; | 23 | import static org.junit.jupiter.api.Assertions.*; |
| 27 | import static org.mockito.ArgumentMatchers.any; | 24 | import static org.mockito.ArgumentMatchers.any; |
| 28 | -import static org.mockito.ArgumentMatchers.anyString; | ||
| 29 | import static org.mockito.ArgumentMatchers.eq; | 25 | import static org.mockito.ArgumentMatchers.eq; |
| 30 | -import static org.mockito.Mockito.mockStatic; | ||
| 31 | import static org.mockito.Mockito.never; | 26 | import static org.mockito.Mockito.never; |
| 32 | -import static org.mockito.Mockito.times; | ||
| 33 | import static org.mockito.Mockito.verify; | 27 | import static org.mockito.Mockito.verify; |
| 34 | import static org.mockito.Mockito.when; | 28 | import static org.mockito.Mockito.when; |
| 35 | 29 | ||
| @@ -52,28 +46,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -52,28 +46,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 52 | @Mock | 46 | @Mock |
| 53 | private ImPrivateMessageService privateMessageService; | 47 | private ImPrivateMessageService privateMessageService; |
| 54 | 48 | ||
| 55 | - // ========== isFriend ========== | ||
| 56 | - | ||
| 57 | - @Test | ||
| 58 | - public void testIsFriend_enabled() { | ||
| 59 | - ImFriendDO friend = ImFriendDO.builder().userId(1L).friendUserId(2L) | ||
| 60 | - .status(CommonStatusEnum.ENABLE.getStatus()).build(); | ||
| 61 | - when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend); | ||
| 62 | - | ||
| 63 | - assertTrue(friendService.isFriend(1L, 2L)); | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - @Test | ||
| 67 | - public void testIsFriend_disabledOrAbsent() { | ||
| 68 | - when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(null); | ||
| 69 | - assertFalse(friendService.isFriend(1L, 2L)); | ||
| 70 | - | ||
| 71 | - ImFriendDO disabled = ImFriendDO.builder().userId(1L).friendUserId(3L) | ||
| 72 | - .status(CommonStatusEnum.DISABLE.getStatus()).build(); | ||
| 73 | - when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 3L)).thenReturn(disabled); | ||
| 74 | - assertFalse(friendService.isFriend(1L, 3L)); | ||
| 75 | - } | ||
| 76 | - | ||
| 77 | // ========== updateFriend ========== | 49 | // ========== updateFriend ========== |
| 78 | 50 | ||
| 79 | @Test | 51 | @Test |
| @@ -152,36 +124,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -152,36 +124,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 152 | verify(imWebSocketService, never()).sendPrivateMessageAsync(any(Long.class), any(ImPrivateMessageDTO.class)); | 124 | verify(imWebSocketService, never()).sendPrivateMessageAsync(any(Long.class), any(ImPrivateMessageDTO.class)); |
| 153 | } | 125 | } |
| 154 | 126 | ||
| 155 | - // ========== addFriend ========== | ||
| 156 | - | ||
| 157 | - @Test | ||
| 158 | - public void testAddFriend_self() { | ||
| 159 | - ServiceException exception = assertThrows(ServiceException.class, | ||
| 160 | - () -> friendService.addFriend(1L, 1L)); | ||
| 161 | - assertEquals(FRIEND_ADD_SELF.getCode(), exception.getCode()); | ||
| 162 | - } | ||
| 163 | - | ||
| 164 | - @Test | ||
| 165 | - public void testAddFriend_success() { | ||
| 166 | - try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 167 | - springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImFriendServiceImpl.class))) | ||
| 168 | - .thenReturn(friendService); | ||
| 169 | - | ||
| 170 | - // 准备 | ||
| 171 | - when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(null); | ||
| 172 | - when(imFriendMapper.selectByUserIdAndFriendUserId(2L, 1L)).thenReturn(null); | ||
| 173 | - | ||
| 174 | - // 调用 | ||
| 175 | - friendService.addFriend(1L, 2L); | ||
| 176 | - | ||
| 177 | - // 断言:校验对方存在 | ||
| 178 | - verify(adminUserApi).validateUser(2L); | ||
| 179 | - // 断言:双向插入 2 条好友关系 | ||
| 180 | - verify(imFriendMapper, times(2)).insert(any(ImFriendDO.class)); | ||
| 181 | - // 断言:FRIEND_ADD 单条入库(双向 WebSocket 推送由 sendPrivateMessage 内部完成,mock 下不可见) | ||
| 182 | - verify(privateMessageService).sendPrivateMessage(eq(1L), any()); | ||
| 183 | - } | ||
| 184 | - } | 127 | + // ========== addFriend0(内部方法,被 becomeFriends / silentReAddFriend 调用) ========== |
| 185 | 128 | ||
| 186 | @Test | 129 | @Test |
| 187 | public void testAddFriend0_existingEnabledSkipsUpdate() { | 130 | public void testAddFriend0_existingEnabledSkipsUpdate() { |
| @@ -191,7 +134,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -191,7 +134,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 191 | when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists); | 134 | when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists); |
| 192 | 135 | ||
| 193 | // 调用 | 136 | // 调用 |
| 194 | - friendService.addFriend0(1L, 2L); | 137 | + friendService.addFriend0(1L, 2L, null, null); |
| 195 | 138 | ||
| 196 | // 断言:不插入,也不更新 | 139 | // 断言:不插入,也不更新 |
| 197 | verify(imFriendMapper, never()).insert(any(ImFriendDO.class)); | 140 | verify(imFriendMapper, never()).insert(any(ImFriendDO.class)); |
| @@ -206,7 +149,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -206,7 +149,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 206 | when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists); | 149 | when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(exists); |
| 207 | 150 | ||
| 208 | // 调用 | 151 | // 调用 |
| 209 | - friendService.addFriend0(1L, 2L); | 152 | + friendService.addFriend0(1L, 2L, null, null); |
| 210 | 153 | ||
| 211 | // 断言:更新 status 为 ENABLE | 154 | // 断言:更新 status 为 ENABLE |
| 212 | ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class); | 155 | ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class); |
| @@ -224,7 +167,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -224,7 +167,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 224 | .thenThrow(new DuplicateKeyException("concurrent insert")); | 167 | .thenThrow(new DuplicateKeyException("concurrent insert")); |
| 225 | 168 | ||
| 226 | // 调用:应被吞掉,不抛异常 | 169 | // 调用:应被吞掉,不抛异常 |
| 227 | - friendService.addFriend0(1L, 2L); | 170 | + friendService.addFriend0(1L, 2L, null, null); |
| 228 | 171 | ||
| 229 | verify(imFriendMapper).insert(any(ImFriendDO.class)); | 172 | verify(imFriendMapper).insert(any(ImFriendDO.class)); |
| 230 | } | 173 | } |
| @@ -232,28 +175,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | @@ -232,28 +175,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { | ||
| 232 | // ========== deleteFriend ========== | 175 | // ========== deleteFriend ========== |
| 233 | 176 | ||
| 234 | @Test | 177 | @Test |
| 235 | - public void testDeleteFriend_success() { | ||
| 236 | - try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 237 | - springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(ImFriendServiceImpl.class))) | ||
| 238 | - .thenReturn(friendService); | ||
| 239 | - | ||
| 240 | - ImFriendDO friend12 = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L) | ||
| 241 | - .status(CommonStatusEnum.ENABLE.getStatus()).build(); | ||
| 242 | - ImFriendDO friend21 = ImFriendDO.builder().id(11L).userId(2L).friendUserId(1L) | ||
| 243 | - .status(CommonStatusEnum.ENABLE.getStatus()).build(); | ||
| 244 | - when(imFriendMapper.selectByUserIdAndFriendUserId(1L, 2L)).thenReturn(friend12); | ||
| 245 | - when(imFriendMapper.selectByUserIdAndFriendUserId(2L, 1L)).thenReturn(friend21); | ||
| 246 | - | ||
| 247 | - friendService.deleteFriend(1L, 2L); | ||
| 248 | - | ||
| 249 | - // 断言:双向更新为 DISABLE | ||
| 250 | - verify(imFriendMapper, times(2)).updateById(any(ImFriendDO.class)); | ||
| 251 | - // 断言:仅给 userId 多端推送 FRIEND_DELETE 事件(friendUserId 不感知) | ||
| 252 | - verify(imWebSocketService).sendPrivateMessageAsync(eq(1L), any(ImPrivateMessageDTO.class)); | ||
| 253 | - } | ||
| 254 | - } | ||
| 255 | - | ||
| 256 | - @Test | ||
| 257 | public void testDeleteFriend0_alreadyDisabled() { | 178 | public void testDeleteFriend0_alreadyDisabled() { |
| 258 | // 准备:已经是 DISABLE,不再更新 | 179 | // 准备:已经是 DISABLE,不再更新 |
| 259 | ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L) | 180 | ImFriendDO exists = ImFriendDO.builder().id(10L).userId(1L).friendUserId(2L) |
yudao-module-im/src/test/java/cn/iocoder/yudao/module/im/service/message/ImPrivateMessageServiceImplTest.java
| @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivate | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivate | ||
| 6 | import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO; | 6 | import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO; |
| 7 | import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; |
| 8 | import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper; | 8 | import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper; |
| 9 | +import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; | ||
| 9 | import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; | 10 | import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; |
| 10 | import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; | 11 | import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; |
| 11 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; | 12 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; |
| @@ -63,7 +64,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -63,7 +64,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 63 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); | 64 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 64 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) | 65 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 65 | .thenReturn(null); | 66 | .thenReturn(null); |
| 66 | - when(friendService.isFriend(1L, 2L)).thenReturn(true); | 67 | + when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.FRIEND); |
| 67 | when(privateMessageMapper.insert(any(ImPrivateMessageDO.class))).thenAnswer(invocation -> { | 68 | when(privateMessageMapper.insert(any(ImPrivateMessageDO.class))).thenAnswer(invocation -> { |
| 68 | ImPrivateMessageDO msg = invocation.getArgument(0); | 69 | ImPrivateMessageDO msg = invocation.getArgument(0); |
| 69 | msg.setId(99L); | 70 | msg.setId(99L); |
| @@ -82,7 +83,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -82,7 +83,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 82 | assertNotNull(result.getSendTime()); | 83 | assertNotNull(result.getSendTime()); |
| 83 | 84 | ||
| 84 | // 验证调用 | 85 | // 验证调用 |
| 85 | - verify(friendService).isFriend(1L, 2L); | 86 | + verify(friendService).getFriendState(1L, 2L); |
| 86 | verify(sensitiveWordService).validateText(reqVO.getContent()); | 87 | verify(sensitiveWordService).validateText(reqVO.getContent()); |
| 87 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); | 88 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); |
| 88 | // 验证推送给接收方和发送方 | 89 | // 验证推送给接收方和发送方 |
| @@ -116,7 +117,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -116,7 +117,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 116 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); | 117 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 117 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) | 118 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 118 | .thenReturn(null); | 119 | .thenReturn(null); |
| 119 | - when(friendService.isFriend(1L, 2L)).thenReturn(false); | 120 | + when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.NONE); |
| 120 | 121 | ||
| 121 | // 调用并断言 | 122 | // 调用并断言 |
| 122 | ServiceException exception = assertThrows(ServiceException.class, | 123 | ServiceException exception = assertThrows(ServiceException.class, |
| @@ -279,7 +280,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | @@ -279,7 +280,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { | ||
| 279 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); | 280 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 280 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) | 281 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 281 | .thenReturn(null); | 282 | .thenReturn(null); |
| 282 | - when(friendService.isFriend(1L, 2L)).thenReturn(true); | 283 | + when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.FRIEND); |
| 283 | doThrow(new ServiceException(MESSAGE_SENSITIVE_WORD_BLOCKED)) | 284 | doThrow(new ServiceException(MESSAGE_SENSITIVE_WORD_BLOCKED)) |
| 284 | .when(sensitiveWordService).validateText(reqVO.getContent()); | 285 | .when(sensitiveWordService).validateText(reqVO.getContent()); |
| 285 | 286 |