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 | 1 | package cn.iocoder.yudao.module.im.service.friend; |
| 2 | 2 | |
| 3 | -import cn.hutool.extra.spring.SpringUtil; | |
| 4 | 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 5 | 4 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 6 | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| ... | ... | @@ -15,21 +14,16 @@ import org.junit.jupiter.api.Test; |
| 15 | 14 | import org.mockito.ArgumentCaptor; |
| 16 | 15 | import org.mockito.InjectMocks; |
| 17 | 16 | import org.mockito.Mock; |
| 18 | -import org.mockito.MockedStatic; | |
| 19 | 17 | import org.springframework.dao.DuplicateKeyException; |
| 20 | 18 | |
| 21 | 19 | import java.time.LocalDateTime; |
| 22 | 20 | import java.util.List; |
| 23 | 21 | |
| 24 | -import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_ADD_SELF; | |
| 25 | 22 | import static cn.iocoder.yudao.module.im.enums.ErrorCodeConstants.FRIEND_NOT_FRIEND; |
| 26 | 23 | import static org.junit.jupiter.api.Assertions.*; |
| 27 | 24 | import static org.mockito.ArgumentMatchers.any; |
| 28 | -import static org.mockito.ArgumentMatchers.anyString; | |
| 29 | 25 | import static org.mockito.ArgumentMatchers.eq; |
| 30 | -import static org.mockito.Mockito.mockStatic; | |
| 31 | 26 | import static org.mockito.Mockito.never; |
| 32 | -import static org.mockito.Mockito.times; | |
| 33 | 27 | import static org.mockito.Mockito.verify; |
| 34 | 28 | import static org.mockito.Mockito.when; |
| 35 | 29 | |
| ... | ... | @@ -52,28 +46,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 52 | 46 | @Mock |
| 53 | 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 | 49 | // ========== updateFriend ========== |
| 78 | 50 | |
| 79 | 51 | @Test |
| ... | ... | @@ -152,36 +124,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 152 | 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 | 129 | @Test |
| 187 | 130 | public void testAddFriend0_existingEnabledSkipsUpdate() { |
| ... | ... | @@ -191,7 +134,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 191 | 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 | 140 | verify(imFriendMapper, never()).insert(any(ImFriendDO.class)); |
| ... | ... | @@ -206,7 +149,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 206 | 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 | 154 | // 断言:更新 status 为 ENABLE |
| 212 | 155 | ArgumentCaptor<ImFriendDO> captor = ArgumentCaptor.forClass(ImFriendDO.class); |
| ... | ... | @@ -224,7 +167,7 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 224 | 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 | 172 | verify(imFriendMapper).insert(any(ImFriendDO.class)); |
| 230 | 173 | } |
| ... | ... | @@ -232,28 +175,6 @@ public class ImFriendServiceImplTest extends BaseMockitoUnitTest { |
| 232 | 175 | // ========== deleteFriend ========== |
| 233 | 176 | |
| 234 | 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 | 178 | public void testDeleteFriend0_alreadyDisabled() { |
| 258 | 179 | // 准备:已经是 DISABLE,不再更新 |
| 259 | 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 | import cn.iocoder.yudao.module.im.controller.admin.message.vo.privates.ImPrivateMessageSendReqVO; |
| 7 | 7 | import cn.iocoder.yudao.module.im.dal.dataobject.message.ImPrivateMessageDO; |
| 8 | 8 | import cn.iocoder.yudao.module.im.dal.mysql.message.ImPrivateMessageMapper; |
| 9 | +import cn.iocoder.yudao.module.im.enums.friend.ImFriendStateEnum; | |
| 9 | 10 | import cn.iocoder.yudao.module.im.enums.message.ImMessageStatusEnum; |
| 10 | 11 | import cn.iocoder.yudao.module.im.enums.message.ImMessageTypeEnum; |
| 11 | 12 | import cn.iocoder.yudao.module.im.service.friend.ImFriendService; |
| ... | ... | @@ -63,7 +64,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { |
| 63 | 64 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 64 | 65 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 65 | 66 | .thenReturn(null); |
| 66 | - when(friendService.isFriend(1L, 2L)).thenReturn(true); | |
| 67 | + when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.FRIEND); | |
| 67 | 68 | when(privateMessageMapper.insert(any(ImPrivateMessageDO.class))).thenAnswer(invocation -> { |
| 68 | 69 | ImPrivateMessageDO msg = invocation.getArgument(0); |
| 69 | 70 | msg.setId(99L); |
| ... | ... | @@ -82,7 +83,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { |
| 82 | 83 | assertNotNull(result.getSendTime()); |
| 83 | 84 | |
| 84 | 85 | // 验证调用 |
| 85 | - verify(friendService).isFriend(1L, 2L); | |
| 86 | + verify(friendService).getFriendState(1L, 2L); | |
| 86 | 87 | verify(sensitiveWordService).validateText(reqVO.getContent()); |
| 87 | 88 | verify(privateMessageMapper).insert(any(ImPrivateMessageDO.class)); |
| 88 | 89 | // 验证推送给接收方和发送方 |
| ... | ... | @@ -116,7 +117,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { |
| 116 | 117 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 117 | 118 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 118 | 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 | 123 | ServiceException exception = assertThrows(ServiceException.class, |
| ... | ... | @@ -279,7 +280,7 @@ public class ImPrivateMessageServiceImplTest extends BaseMockitoUnitTest { |
| 279 | 280 | ImPrivateMessageSendReqVO reqVO = buildSendReqVO(); |
| 280 | 281 | when(privateMessageMapper.selectBySenderIdAndClientMessageId(1L, "test-uuid-001")) |
| 281 | 282 | .thenReturn(null); |
| 282 | - when(friendService.isFriend(1L, 2L)).thenReturn(true); | |
| 283 | + when(friendService.getFriendState(1L, 2L)).thenReturn(ImFriendStateEnum.FRIEND); | |
| 283 | 284 | doThrow(new ServiceException(MESSAGE_SENSITIVE_WORD_BLOCKED)) |
| 284 | 285 | .when(sensitiveWordService).validateText(reqVO.getContent()); |
| 285 | 286 | ... | ... |