package com.greenorange.promotion.junit; import com.greenorange.promotion.model.dto.userAccount.UserAccountUpdateRequest; import com.greenorange.promotion.model.entity.UserAccount; import com.greenorange.promotion.service.common.CommonService; import com.greenorange.promotion.service.settle.impl.UserAccountServiceImpl; import jakarta.servlet.http.HttpServletRequest; 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.Spy; import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class UserAccountServiceImplTest { @Spy @InjectMocks private UserAccountServiceImpl userAccountService; // Spy + InjectMocks:用真实的 serviceImpl,但可以对它的方法做部分 stub @Mock private CommonService commonService; // Mock CommonService,用于模拟 copyProperties @Mock private HttpServletRequest request; // Mock HttpServletRequest,用于模拟获取 userId @Test void updateUserAccount_shouldCopyProperties_setUserId_andUpdateById() { // --- Arrange 准备阶段 --- Long userId = 456L; // 模拟从 request 中拿到当前登录用户 ID when(request.getAttribute("userId")).thenReturn(userId); // 构造更新请求 DTO,并设置要更新的账户 ID UserAccountUpdateRequest req = new UserAccountUpdateRequest(); req.setId(99L); req.setCardHolder("李四"); req.setIdCardNumber("110101199002022345"); req.setPhoneNumber("15900001111"); req.setBankCardNumber("6222020202020202"); req.setOpenBank("中国农业银行"); // 准备一个空实体,模拟 commonService.copyProperties 拷贝结果 UserAccount stubEntity = new UserAccount(); // 假设 copyProperties 会拷贝所有字段,包括 id stubEntity.setId(req.getId()); stubEntity.setCardHolder(req.getCardHolder()); stubEntity.setIdCardNumber(req.getIdCardNumber()); stubEntity.setPhoneNumber(req.getPhoneNumber()); stubEntity.setBankCardNumber(req.getBankCardNumber()); stubEntity.setOpenBank(req.getOpenBank()); // stub copyProperties 返回我们准备的 stubEntity when(commonService.copyProperties(req, UserAccount.class)) .thenReturn(stubEntity); // 对 Spy 的 updateById(...) 方法做 stub,避免走到 MyBatis-Plus 真逻辑 doReturn(true).when(userAccountService).updateById(any(UserAccount.class)); // --- Act 执行阶段 --- userAccountService.updateUserAccount(req, request); // 方法内部执行顺序: // 1. 取 request.getAttribute("userId") -> 456L // 2. commonService.copyProperties(req, UserAccount.class) -> stubEntity // 3. stubEntity.setUserId(456L) // 4. 调用 updateById(stubEntity) // --- Assert 验证阶段 --- // 捕获 updateById 调用时传入的参数 ArgumentCaptor captor = ArgumentCaptor.forClass(UserAccount.class); verify(userAccountService).updateById(captor.capture()); UserAccount updated = captor.getValue(); // 验证传给 updateById 的正是 stubEntity 对象 assertSame(stubEntity, updated, "应该传入同一个 stubEntity 实例"); // 验证 userId 已正确赋值 assertEquals(userId, updated.getUserId(), "userId 应该从 request 中取出并赋值"); // 验证其他字段都被 copyProperties 拷贝过来,包括账户 ID assertEquals(req.getId(), updated.getId(), "账户 ID 应保持一致"); assertEquals("李四", updated.getCardHolder(), "持卡人应一致"); assertEquals("110101199002022345", updated.getIdCardNumber(), "身份证号应一致"); assertEquals("15900001111", updated.getPhoneNumber(), "手机号应一致"); assertEquals("6222020202020202", updated.getBankCardNumber(),"银行卡号应一致"); assertEquals("中国农业银行", updated.getOpenBank(), "开户银行应一致"); } }