Commit 9d5d8c9527ca81c1a41633565d7cb62ee55d92c2
1 parent
6ed09714
fix(product): 修正虚拟评价创建契约并启用商品评价单测
Showing
4 changed files
with
311 additions
and
135 deletions
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/controller/admin/comment/vo/ProductCommentCreateReqVO.java
| ... | ... | @@ -11,12 +11,6 @@ import java.util.List; |
| 11 | 11 | @Data |
| 12 | 12 | public class ProductCommentCreateReqVO { |
| 13 | 13 | |
| 14 | - @Schema(description = "评价人", requiredMode = Schema.RequiredMode.REQUIRED, example = "16868") | |
| 15 | - private Long userId; | |
| 16 | - | |
| 17 | - @Schema(description = "评价订单项", requiredMode = Schema.RequiredMode.REQUIRED, example = "19292") | |
| 18 | - private Long orderItemId; | |
| 19 | - | |
| 20 | 14 | @Schema(description = "评价人名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小姑凉") |
| 21 | 15 | @NotNull(message = "评价人名称不能为空") |
| 22 | 16 | private String userNickname; | ... | ... |
yudao-module-mall/yudao-module-product/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java
| ... | ... | @@ -40,6 +40,7 @@ public interface ProductCommentConvert { |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | default ProductCommentDO convert(ProductCommentCreateReqVO createReq, ProductSpuDO spu, ProductSkuDO sku) { |
| 43 | + // 管理后台添加的是虚拟评价,不关联会员和订单,userId 固定为 0:https://github.com/YunaiV/ruoyi-vue-pro/issues/1277 | |
| 43 | 44 | ProductCommentDO comment = BeanUtils.toBean(createReq, ProductCommentDO.class) |
| 44 | 45 | .setVisible(true).setUserId(0L).setAnonymous(false) |
| 45 | 46 | .setScores(convertScores(createReq.getDescriptionScores(), createReq.getBenefitScores())); | ... | ... |
yudao-module-mall/yudao-module-product/src/test/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImplTest.java
| 1 | 1 | package cn.iocoder.yudao.module.product.service.comment; |
| 2 | 2 | |
| 3 | -import cn.hutool.core.date.DateUtil; | |
| 4 | -import cn.hutool.core.util.RandomUtil; | |
| 5 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils; | |
| 7 | 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 6 | +import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | |
| 7 | +import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | |
| 8 | +import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO; | |
| 9 | +import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentCreateReqVO; | |
| 8 | 10 | import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentPageReqVO; |
| 9 | 11 | import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentReplyReqVO; |
| 10 | -import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentRespVO; | |
| 11 | 12 | import cn.iocoder.yudao.module.product.controller.admin.comment.vo.ProductCommentUpdateVisibleReqVO; |
| 12 | 13 | import cn.iocoder.yudao.module.product.controller.app.comment.vo.AppCommentPageReqVO; |
| 13 | 14 | import cn.iocoder.yudao.module.product.dal.dataobject.comment.ProductCommentDO; |
| 15 | +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | |
| 16 | +import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | |
| 14 | 17 | import cn.iocoder.yudao.module.product.dal.mysql.comment.ProductCommentMapper; |
| 15 | 18 | import cn.iocoder.yudao.module.product.enums.comment.ProductCommentScoresEnum; |
| 16 | 19 | import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; |
| 17 | 20 | import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; |
| 18 | 21 | import jakarta.annotation.Resource; |
| 19 | -import org.junit.jupiter.api.Disabled; | |
| 20 | 22 | import org.junit.jupiter.api.Test; |
| 21 | 23 | import org.springframework.context.annotation.Import; |
| 22 | -import org.springframework.context.annotation.Lazy; | |
| 24 | +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; | |
| 23 | 25 | import org.springframework.test.context.bean.override.mockito.MockitoBean; |
| 24 | 26 | |
| 25 | -import java.time.LocalDateTime; | |
| 26 | -import java.util.Date; | |
| 27 | +import java.util.List; | |
| 28 | +import java.util.function.Consumer; | |
| 27 | 29 | |
| 30 | +import static cn.hutool.core.util.RandomUtil.randomEle; | |
| 31 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | |
| 32 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; | |
| 28 | 33 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 29 | 34 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 30 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 31 | -import static org.junit.jupiter.api.Assertions.assertEquals; | |
| 32 | -import static org.junit.jupiter.api.Assertions.assertFalse; | |
| 35 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | |
| 36 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; | |
| 37 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; | |
| 38 | +import static java.util.Collections.singletonList; | |
| 39 | +import static org.junit.jupiter.api.Assertions.*; | |
| 40 | +import static org.mockito.ArgumentMatchers.any; | |
| 41 | +import static org.mockito.ArgumentMatchers.eq; | |
| 42 | +import static org.mockito.Mockito.*; | |
| 33 | 43 | |
| 34 | 44 | // TODO 芋艿:单测详细 review 下 |
| 35 | 45 | /** |
| ... | ... | @@ -37,159 +47,328 @@ import static org.junit.jupiter.api.Assertions.assertFalse; |
| 37 | 47 | * |
| 38 | 48 | * @author wangzhs |
| 39 | 49 | */ |
| 40 | -@Disabled // TODO 芋艿:后续 fix 补充的单测 | |
| 50 | +// DONE 芋艿:后续 fix 补充的单测 | |
| 41 | 51 | @Import(ProductCommentServiceImpl.class) |
| 42 | 52 | public class ProductCommentServiceImplTest extends BaseDbUnitTest { |
| 43 | 53 | |
| 44 | 54 | @Resource |
| 45 | - private ProductCommentMapper productCommentMapper; | |
| 55 | + private ProductCommentServiceImpl productCommentService; | |
| 46 | 56 | |
| 47 | 57 | @Resource |
| 48 | - @Lazy | |
| 49 | - private ProductCommentServiceImpl productCommentService; | |
| 58 | + private ProductCommentMapper productCommentMapper; | |
| 50 | 59 | |
| 51 | 60 | @MockitoBean |
| 52 | 61 | private ProductSpuService productSpuService; |
| 53 | 62 | @MockitoBean |
| 54 | 63 | private ProductSkuService productSkuService; |
| 64 | + @MockitoBean | |
| 65 | + private MemberUserApi memberUserApi; | |
| 66 | + | |
| 67 | + // ========== 管理后台添加虚拟评价 ========== | |
| 68 | + | |
| 69 | + @Test | |
| 70 | + public void testCreateComment_success() { | |
| 71 | + // 准备参数 | |
| 72 | + ProductCommentCreateReqVO reqVO = randomPojo(ProductCommentCreateReqVO.class, o -> o | |
| 73 | + .setDescriptionScores(ProductCommentScoresEnum.FIVE.getScores()) | |
| 74 | + .setBenefitScores(ProductCommentScoresEnum.FOUR.getScores())); | |
| 75 | + // mock 方法 | |
| 76 | + ProductSkuDO sku = mockSku(reqVO.getSkuId()); | |
| 77 | + ProductSpuDO spu = mockSpu(sku.getSpuId()); | |
| 55 | 78 | |
| 56 | - public String generateNo() { | |
| 57 | - return DateUtil.format(new Date(), "yyyyMMddHHmmss") + RandomUtil.randomInt(100000, 999999); | |
| 79 | + // 调用 | |
| 80 | + productCommentService.createComment(reqVO); | |
| 81 | + // 断言:虚拟评价不关联会员和订单 | |
| 82 | + List<ProductCommentDO> comments = productCommentMapper.selectList(); | |
| 83 | + assertEquals(1, comments.size()); | |
| 84 | + ProductCommentDO comment = comments.get(0); | |
| 85 | + assertPojoEquals(reqVO, comment); | |
| 86 | + assertEquals(0L, comment.getUserId()); | |
| 87 | + assertNull(comment.getOrderId()); | |
| 88 | + assertNull(comment.getOrderItemId()); | |
| 89 | + assertTrue(comment.getVisible()); | |
| 90 | + assertFalse(comment.getAnonymous()); | |
| 91 | + assertEquals(4, comment.getScores()); // (5 + 4) / 2 向下取整 | |
| 92 | + // 断言:商品信息 | |
| 93 | + assertEquals(spu.getId(), comment.getSpuId()); | |
| 94 | + assertEquals(spu.getName(), comment.getSpuName()); | |
| 95 | + assertEquals(sku.getPicUrl(), comment.getSkuPicUrl()); | |
| 96 | + assertEquals(sku.getProperties(), comment.getSkuProperties()); | |
| 97 | + } | |
| 98 | + | |
| 99 | + @Test | |
| 100 | + public void testCreateComment_ignoreUserIdAndOrderItemId() throws Exception { | |
| 101 | + // 准备参数:旧调用方仍传入 userId、orderItemId,使用 Spring MVC 默认的 Jackson2ObjectMapperBuilder 反序列化 | |
| 102 | + String json = "{\"userId\":968,\"orderItemId\":1024,\"skuId\":1,\"userNickname\":\"芋艿\"," | |
| 103 | + + "\"userAvatar\":\"https://www.iocoder.cn/1.png\",\"descriptionScores\":5,\"benefitScores\":5," | |
| 104 | + + "\"content\":\"好评\",\"picUrls\":[]}"; | |
| 105 | + ProductCommentCreateReqVO reqVO = Jackson2ObjectMapperBuilder.json().build() | |
| 106 | + .readValue(json, ProductCommentCreateReqVO.class); | |
| 107 | + // mock 方法 | |
| 108 | + mockSpu(mockSku(reqVO.getSkuId()).getSpuId()); | |
| 109 | + | |
| 110 | + // 调用 | |
| 111 | + productCommentService.createComment(reqVO); | |
| 112 | + // 断言 | |
| 113 | + ProductCommentDO comment = productCommentMapper.selectOne(ProductCommentDO::getSkuId, 1L); | |
| 114 | + assertEquals("芋艿", comment.getUserNickname()); | |
| 115 | + assertEquals(0L, comment.getUserId()); | |
| 116 | + assertNull(comment.getOrderItemId()); | |
| 58 | 117 | } |
| 59 | 118 | |
| 60 | - public Long generateId() { | |
| 61 | - return RandomUtil.randomLong(100000, 999999); | |
| 119 | + @Test | |
| 120 | + public void testCreateComment_skuNotExists() { | |
| 121 | + // 准备参数 | |
| 122 | + ProductCommentCreateReqVO reqVO = randomPojo(ProductCommentCreateReqVO.class); | |
| 123 | + | |
| 124 | + // 调用,并断言异常 | |
| 125 | + assertServiceException(() -> productCommentService.createComment(reqVO), SKU_NOT_EXISTS); | |
| 126 | + assertEquals(0L, productCommentMapper.selectCount()); | |
| 62 | 127 | } |
| 63 | 128 | |
| 129 | + // ========== 会员评价订单项 ========== | |
| 130 | + | |
| 64 | 131 | @Test |
| 65 | - public void testCreateCommentAndGet_success() { | |
| 66 | - // mock 测试 | |
| 67 | - ProductCommentDO productComment = randomPojo(ProductCommentDO.class); | |
| 68 | - productCommentMapper.insert(productComment); | |
| 132 | + public void testCreateCommentByMember_success() { | |
| 133 | + // 准备参数 | |
| 134 | + ProductCommentCreateReqDTO reqDTO = randomPojo(ProductCommentCreateReqDTO.class, o -> o | |
| 135 | + .setDescriptionScores(ProductCommentScoresEnum.THREE.getScores()) | |
| 136 | + .setBenefitScores(ProductCommentScoresEnum.FOUR.getScores())); | |
| 137 | + // mock 数据:同一 SKU 已有虚拟评价,不影响会员评价 | |
| 138 | + productCommentMapper.insert(randomCommentDO(o -> o.setUserId(0L).setOrderId(null).setOrderItemId(null) | |
| 139 | + .setSkuId(reqDTO.getSkuId()))); | |
| 140 | + // mock 方法 | |
| 141 | + ProductSkuDO sku = mockSku(reqDTO.getSkuId()); | |
| 142 | + ProductSpuDO spu = mockSpu(sku.getSpuId()); | |
| 143 | + MemberUserRespDTO user = randomPojo(MemberUserRespDTO.class, o -> o.setId(reqDTO.getUserId())); | |
| 144 | + when(memberUserApi.getUser(eq(reqDTO.getUserId()))).thenReturn(user); | |
| 69 | 145 | |
| 146 | + // 调用 | |
| 147 | + Long commentId = productCommentService.createComment(reqDTO); | |
| 70 | 148 | // 断言 |
| 71 | - // 校验记录的属性是否正确 | |
| 72 | - ProductCommentDO comment = productCommentMapper.selectById(productComment.getId()); | |
| 73 | - assertPojoEquals(productComment, comment); | |
| 149 | + ProductCommentDO comment = productCommentMapper.selectById(commentId); | |
| 150 | + assertPojoEquals(reqDTO, comment); | |
| 151 | + assertEquals(user.getNickname(), comment.getUserNickname()); | |
| 152 | + assertEquals(user.getAvatar(), comment.getUserAvatar()); | |
| 153 | + assertEquals(3, comment.getScores()); // (3 + 4) / 2 向下取整 | |
| 154 | + assertEquals(spu.getId(), comment.getSpuId()); | |
| 155 | + assertEquals(spu.getName(), comment.getSpuName()); | |
| 156 | + assertEquals(sku.getPicUrl(), comment.getSkuPicUrl()); | |
| 157 | + assertEquals(sku.getProperties(), comment.getSkuProperties()); | |
| 74 | 158 | } |
| 75 | 159 | |
| 76 | 160 | @Test |
| 77 | - public void testGetCommentPage_success() { | |
| 161 | + public void testCreateCommentByMember_orderExists() { | |
| 162 | + // mock 数据:该会员已评价该订单项 | |
| 163 | + ProductCommentDO dbComment = randomCommentDO(); | |
| 164 | + productCommentMapper.insert(dbComment); | |
| 78 | 165 | // 准备参数 |
| 79 | - ProductCommentDO productComment = randomPojo(ProductCommentDO.class, o -> { | |
| 166 | + ProductCommentCreateReqDTO reqDTO = randomPojo(ProductCommentCreateReqDTO.class, o -> o | |
| 167 | + .setUserId(dbComment.getUserId()).setOrderItemId(dbComment.getOrderItemId())); | |
| 168 | + // mock 方法 | |
| 169 | + mockSpu(mockSku(reqDTO.getSkuId()).getSpuId()); | |
| 170 | + | |
| 171 | + // 调用,并断言异常 | |
| 172 | + assertServiceException(() -> productCommentService.createComment(reqDTO), COMMENT_ORDER_EXISTS); | |
| 173 | + assertEquals(1L, productCommentMapper.selectCount()); | |
| 174 | + verify(memberUserApi, never()).getUser(any()); | |
| 175 | + } | |
| 176 | + | |
| 177 | + // ========== 查询评价 ========== | |
| 178 | + | |
| 179 | + @Test | |
| 180 | + public void testGetComment_success() { | |
| 181 | + // mock 数据 | |
| 182 | + ProductCommentDO dbComment = randomCommentDO(); | |
| 183 | + productCommentMapper.insert(dbComment); | |
| 184 | + | |
| 185 | + // 调用 | |
| 186 | + ProductCommentDO comment = productCommentService.getComment(dbComment.getId()); | |
| 187 | + // 断言 | |
| 188 | + assertPojoEquals(dbComment, comment); | |
| 189 | + } | |
| 190 | + | |
| 191 | + @Test | |
| 192 | + public void testGetComment_notExists() { | |
| 193 | + // 调用,并断言异常 | |
| 194 | + assertServiceException(() -> productCommentService.getComment(randomLongId()), COMMENT_NOT_EXISTS); | |
| 195 | + } | |
| 196 | + | |
| 197 | + @Test | |
| 198 | + public void testGetCommentPage_success() { | |
| 199 | + // mock 数据 | |
| 200 | + ProductCommentDO dbComment = randomCommentDO(o -> { // 等会查询到 | |
| 80 | 201 | o.setUserNickname("王二狗"); |
| 202 | + o.setOrderId(1L); | |
| 203 | + o.setSpuId(2L); | |
| 81 | 204 | o.setSpuName("感冒药"); |
| 82 | 205 | o.setScores(ProductCommentScoresEnum.FOUR.getScores()); |
| 83 | 206 | o.setReplyStatus(Boolean.TRUE); |
| 84 | - o.setVisible(Boolean.TRUE); | |
| 85 | - o.setId(generateId()); | |
| 86 | - o.setUserId(generateId()); | |
| 87 | - o.setAnonymous(Boolean.TRUE); | |
| 88 | - o.setOrderId(generateId()); | |
| 89 | - o.setOrderItemId(generateId()); | |
| 90 | - o.setSpuId(generateId()); | |
| 91 | - o.setSkuId(generateId()); | |
| 92 | - o.setDescriptionScores(ProductCommentScoresEnum.FOUR.getScores()); | |
| 93 | - o.setBenefitScores(ProductCommentScoresEnum.FOUR.getScores()); | |
| 94 | - o.setContent("真好吃"); | |
| 95 | - o.setReplyUserId(generateId()); | |
| 96 | - o.setReplyContent("确实"); | |
| 97 | - o.setReplyTime(LocalDateTime.now()); | |
| 98 | - o.setCreateTime(LocalDateTime.now()); | |
| 99 | - o.setUpdateTime(LocalDateTime.now()); | |
| 207 | + o.setCreateTime(buildTime(2023, 2, 1)); | |
| 208 | + o.setSkuProperties(null); // ProductSkuDO.Property 不可序列化,cloneIgnoreId 无法深拷贝 | |
| 100 | 209 | }); |
| 101 | - productCommentMapper.insert(productComment); | |
| 102 | - | |
| 103 | - Long orderId = productComment.getOrderId(); | |
| 104 | - Long spuId = productComment.getSpuId(); | |
| 105 | - | |
| 210 | + productCommentMapper.insert(dbComment); | |
| 106 | 211 | // 测试 userNickname 不匹配 |
| 107 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setUserNickname("王三").setScores(ProductCommentScoresEnum.ONE.getScores()))); | |
| 212 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setUserNickname("王三"))); | |
| 108 | 213 | // 测试 orderId 不匹配 |
| 109 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setOrderId(generateId()))); | |
| 214 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setOrderId(10L))); | |
| 110 | 215 | // 测试 spuId 不匹配 |
| 111 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setSpuId(generateId()))); | |
| 216 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setSpuId(20L))); | |
| 112 | 217 | // 测试 spuName 不匹配 |
| 113 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setSpuName("感康"))); | |
| 218 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setSpuName("感康"))); | |
| 114 | 219 | // 测试 scores 不匹配 |
| 115 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setScores(ProductCommentScoresEnum.ONE.getScores()))); | |
| 116 | - // 测试 replied 不匹配 | |
| 117 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setReplyStatus(Boolean.FALSE))); | |
| 118 | - // 测试 visible 不匹配 | |
| 119 | - productCommentMapper.insert(cloneIgnoreId(productComment, o -> o.setVisible(Boolean.FALSE))); | |
| 220 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setScores(ProductCommentScoresEnum.ONE.getScores()))); | |
| 221 | + // 测试 replyStatus 不匹配 | |
| 222 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setReplyStatus(Boolean.FALSE))); | |
| 223 | + // 测试 createTime 不匹配 | |
| 224 | + productCommentMapper.insert(cloneIgnoreId(dbComment, o -> o.setCreateTime(buildTime(2023, 3, 1)))); | |
| 225 | + // 准备参数 | |
| 226 | + ProductCommentPageReqVO reqVO = new ProductCommentPageReqVO(); | |
| 227 | + reqVO.setUserNickname("王二"); | |
| 228 | + reqVO.setOrderId(1L); | |
| 229 | + reqVO.setSpuId(2L); | |
| 230 | + reqVO.setSpuName("感冒"); | |
| 231 | + reqVO.setScores(ProductCommentScoresEnum.FOUR.getScores()); | |
| 232 | + reqVO.setReplyStatus(Boolean.TRUE); | |
| 233 | + reqVO.setCreateTime(buildBetweenTime(2023, 1, 1, 2023, 2, 28)); | |
| 120 | 234 | |
| 121 | 235 | // 调用 |
| 122 | - ProductCommentPageReqVO productCommentPageReqVO = new ProductCommentPageReqVO(); | |
| 123 | - productCommentPageReqVO.setUserNickname("王二"); | |
| 124 | - productCommentPageReqVO.setOrderId(orderId); | |
| 125 | - productCommentPageReqVO.setSpuId(spuId); | |
| 126 | - productCommentPageReqVO.setSpuName("感冒药"); | |
| 127 | - productCommentPageReqVO.setScores(ProductCommentScoresEnum.FOUR.getScores()); | |
| 128 | - productCommentPageReqVO.setReplyStatus(Boolean.TRUE); | |
| 129 | - | |
| 130 | - PageResult<ProductCommentDO> commentPage = productCommentService.getCommentPage(productCommentPageReqVO); | |
| 131 | - PageResult<ProductCommentRespVO> result = BeanUtils.toBean(productCommentMapper.selectPage(productCommentPageReqVO), | |
| 132 | - ProductCommentRespVO.class); | |
| 133 | - assertEquals(result.getTotal(), commentPage.getTotal()); | |
| 236 | + PageResult<ProductCommentDO> pageResult = productCommentService.getCommentPage(reqVO); | |
| 237 | + // 断言 | |
| 238 | + assertEquals(1, pageResult.getTotal()); | |
| 239 | + assertEquals(1, pageResult.getList().size()); | |
| 240 | + assertPojoEquals(dbComment, pageResult.getList().get(0)); | |
| 241 | + } | |
| 134 | 242 | |
| 135 | - PageResult<ProductCommentDO> all = productCommentService.getCommentPage(new ProductCommentPageReqVO()); | |
| 136 | - assertEquals(8, all.getTotal()); | |
| 243 | + @Test | |
| 244 | + public void testGetAppCommentPage_success() { | |
| 245 | + // mock 数据 | |
| 246 | + ProductCommentDO goodComment = randomCommentDO(o -> o.setSpuId(1L).setVisible(Boolean.TRUE) | |
| 247 | + .setScores(ProductCommentScoresEnum.FIVE.getScores()) | |
| 248 | + .setSkuProperties(null)); // ProductSkuDO.Property 不可序列化,cloneIgnoreId 无法深拷贝 | |
| 249 | + productCommentMapper.insert(goodComment); | |
| 250 | + ProductCommentDO mediocreComment = cloneIgnoreId(goodComment, o -> o.setScores(ProductCommentScoresEnum.THREE.getScores())); | |
| 251 | + productCommentMapper.insert(mediocreComment); | |
| 252 | + ProductCommentDO negativeComment = cloneIgnoreId(goodComment, o -> o.setScores(ProductCommentScoresEnum.ONE.getScores())); | |
| 253 | + productCommentMapper.insert(negativeComment); | |
| 254 | + // 测试 visible 不匹配 | |
| 255 | + productCommentMapper.insert(cloneIgnoreId(mediocreComment, o -> o.setVisible(Boolean.FALSE))); | |
| 256 | + // 测试 spuId 不匹配 | |
| 257 | + productCommentMapper.insert(cloneIgnoreId(mediocreComment, o -> o.setSpuId(2L))); | |
| 258 | + | |
| 259 | + // 调用 + 断言:全部可见评价 | |
| 260 | + PageResult<ProductCommentDO> allResult = productCommentService.getCommentPage( | |
| 261 | + new AppCommentPageReqVO().setSpuId(1L), Boolean.TRUE); | |
| 262 | + assertEquals(3, allResult.getTotal()); | |
| 263 | + // 调用 + 断言:好评 | |
| 264 | + PageResult<ProductCommentDO> goodResult = productCommentService.getCommentPage( | |
| 265 | + new AppCommentPageReqVO().setSpuId(1L).setType(AppCommentPageReqVO.GOOD_COMMENT), Boolean.TRUE); | |
| 266 | + assertEquals(1, goodResult.getTotal()); | |
| 267 | + assertPojoEquals(goodComment, goodResult.getList().get(0)); | |
| 268 | + // 调用 + 断言:中评 | |
| 269 | + PageResult<ProductCommentDO> mediocreResult = productCommentService.getCommentPage( | |
| 270 | + new AppCommentPageReqVO().setSpuId(1L).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); | |
| 271 | + assertEquals(1, mediocreResult.getTotal()); | |
| 272 | + assertPojoEquals(mediocreComment, mediocreResult.getList().get(0)); | |
| 273 | + // 调用 + 断言:差评 | |
| 274 | + PageResult<ProductCommentDO> negativeResult = productCommentService.getCommentPage( | |
| 275 | + new AppCommentPageReqVO().setSpuId(1L).setType(AppCommentPageReqVO.NEGATIVE_COMMENT), Boolean.TRUE); | |
| 276 | + assertEquals(1, negativeResult.getTotal()); | |
| 277 | + assertPojoEquals(negativeComment, negativeResult.getList().get(0)); | |
| 278 | + // 调用 + 断言:不过滤可见性时,包含隐藏的中评 | |
| 279 | + PageResult<ProductCommentDO> mediocreAllResult = productCommentService.getCommentPage( | |
| 280 | + new AppCommentPageReqVO().setSpuId(1L).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), null); | |
| 281 | + assertEquals(2, mediocreAllResult.getTotal()); | |
| 282 | + } | |
| 137 | 283 | |
| 138 | - // 测试获取所有商品分页评论数据 | |
| 139 | - PageResult<ProductCommentDO> result1 = productCommentService.getCommentPage(new AppCommentPageReqVO(), Boolean.TRUE); | |
| 140 | - assertEquals(7, result1.getTotal()); | |
| 284 | + // ========== 更新评价 ========== | |
| 141 | 285 | |
| 142 | - // 测试获取所有商品分页中评数据 | |
| 143 | - PageResult<ProductCommentDO> result2 = productCommentService.getCommentPage(new AppCommentPageReqVO().setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); | |
| 144 | - assertEquals(2, result2.getTotal()); | |
| 286 | + @Test | |
| 287 | + public void testUpdateCommentVisible_success() { | |
| 288 | + // mock 数据 | |
| 289 | + ProductCommentDO dbComment = randomCommentDO(o -> o.setVisible(Boolean.TRUE)); | |
| 290 | + productCommentMapper.insert(dbComment); | |
| 291 | + // 准备参数 | |
| 292 | + ProductCommentUpdateVisibleReqVO reqVO = new ProductCommentUpdateVisibleReqVO(); | |
| 293 | + reqVO.setId(dbComment.getId()); | |
| 294 | + reqVO.setVisible(Boolean.FALSE); | |
| 145 | 295 | |
| 146 | - // 测试获取指定 spuId 商品分页中评数据 | |
| 147 | - PageResult<ProductCommentDO> result3 = productCommentService.getCommentPage(new AppCommentPageReqVO().setSpuId(spuId).setType(AppCommentPageReqVO.MEDIOCRE_COMMENT), Boolean.TRUE); | |
| 148 | - assertEquals(2, result3.getTotal()); | |
| 296 | + // 调用 | |
| 297 | + productCommentService.updateCommentVisible(reqVO); | |
| 298 | + // 断言 | |
| 299 | + ProductCommentDO comment = productCommentMapper.selectById(dbComment.getId()); | |
| 300 | + assertFalse(comment.getVisible()); | |
| 301 | + assertPojoEquals(dbComment, comment, "visible", "updater", "updateTime"); | |
| 302 | + } | |
| 149 | 303 | |
| 150 | - // 测试分页 tab count | |
| 151 | - //AppCommentStatisticsRespVO tabsCount = productCommentService.getCommentStatistics(spuId, Boolean.TRUE); | |
| 152 | - //assertEquals(4, tabsCount.getGoodCount()); | |
| 153 | - //assertEquals(2, tabsCount.getMediocreCount()); | |
| 154 | - //assertEquals(0, tabsCount.getNegativeCount()); | |
| 304 | + @Test | |
| 305 | + public void testUpdateCommentVisible_notExists() { | |
| 306 | + // 准备参数 | |
| 307 | + ProductCommentUpdateVisibleReqVO reqVO = new ProductCommentUpdateVisibleReqVO(); | |
| 308 | + reqVO.setId(randomLongId()); | |
| 309 | + reqVO.setVisible(Boolean.FALSE); | |
| 155 | 310 | |
| 311 | + // 调用,并断言异常 | |
| 312 | + assertServiceException(() -> productCommentService.updateCommentVisible(reqVO), COMMENT_NOT_EXISTS); | |
| 156 | 313 | } |
| 157 | 314 | |
| 158 | 315 | @Test |
| 159 | - public void testUpdateCommentVisible_success() { | |
| 160 | - // mock 测试 | |
| 161 | - ProductCommentDO productComment = randomPojo(ProductCommentDO.class, o -> { | |
| 162 | - o.setVisible(Boolean.TRUE); | |
| 163 | - }); | |
| 164 | - productCommentMapper.insert(productComment); | |
| 316 | + public void testReplyComment_success() { | |
| 317 | + // mock 数据 | |
| 318 | + ProductCommentDO dbComment = randomCommentDO(o -> o.setReplyStatus(Boolean.FALSE) | |
| 319 | + .setReplyUserId(null).setReplyContent(null).setReplyTime(null)); | |
| 320 | + productCommentMapper.insert(dbComment); | |
| 321 | + // 准备参数 | |
| 322 | + ProductCommentReplyReqVO reqVO = new ProductCommentReplyReqVO(); | |
| 323 | + reqVO.setId(dbComment.getId()); | |
| 324 | + reqVO.setReplyContent("测试"); | |
| 325 | + Long userId = randomLongId(); | |
| 165 | 326 | |
| 166 | - Long productCommentId = productComment.getId(); | |
| 327 | + // 调用 | |
| 328 | + productCommentService.replyComment(reqVO, userId); | |
| 329 | + // 断言 | |
| 330 | + ProductCommentDO comment = productCommentMapper.selectById(dbComment.getId()); | |
| 331 | + assertTrue(comment.getReplyStatus()); | |
| 332 | + assertEquals(userId, comment.getReplyUserId()); | |
| 333 | + assertEquals("测试", comment.getReplyContent()); | |
| 334 | + assertNotNull(comment.getReplyTime()); | |
| 335 | + } | |
| 167 | 336 | |
| 168 | - ProductCommentUpdateVisibleReqVO updateReqVO = new ProductCommentUpdateVisibleReqVO(); | |
| 169 | - updateReqVO.setId(productCommentId); | |
| 170 | - updateReqVO.setVisible(Boolean.FALSE); | |
| 171 | - productCommentService.updateCommentVisible(updateReqVO); | |
| 337 | + @Test | |
| 338 | + public void testReplyComment_notExists() { | |
| 339 | + // 准备参数 | |
| 340 | + ProductCommentReplyReqVO reqVO = new ProductCommentReplyReqVO(); | |
| 341 | + reqVO.setId(randomLongId()); | |
| 342 | + reqVO.setReplyContent("测试"); | |
| 172 | 343 | |
| 173 | - ProductCommentDO productCommentDO = productCommentMapper.selectById(productCommentId); | |
| 174 | - assertFalse(productCommentDO.getVisible()); | |
| 344 | + // 调用,并断言异常 | |
| 345 | + assertServiceException(() -> productCommentService.replyComment(reqVO, randomLongId()), COMMENT_NOT_EXISTS); | |
| 175 | 346 | } |
| 176 | 347 | |
| 348 | + // ========== 随机对象 ========== | |
| 177 | 349 | |
| 178 | - @Test | |
| 179 | - public void testCommentReply_success() { | |
| 180 | - // mock 测试 | |
| 181 | - ProductCommentDO productComment = randomPojo(ProductCommentDO.class); | |
| 182 | - productCommentMapper.insert(productComment); | |
| 183 | - | |
| 184 | - Long productCommentId = productComment.getId(); | |
| 350 | + private ProductSkuDO mockSku(Long skuId) { | |
| 351 | + ProductSkuDO sku = randomPojo(ProductSkuDO.class, o -> o.setId(skuId) | |
| 352 | + .setProperties(singletonList(new ProductSkuDO.Property(1L, "颜色", 2L, "红色")))); | |
| 353 | + when(productSkuService.getSku(eq(skuId), eq(true))).thenReturn(sku); | |
| 354 | + return sku; | |
| 355 | + } | |
| 185 | 356 | |
| 186 | - ProductCommentReplyReqVO replyVO = new ProductCommentReplyReqVO(); | |
| 187 | - replyVO.setId(productCommentId); | |
| 188 | - replyVO.setReplyContent("测试"); | |
| 189 | - productCommentService.replyComment(replyVO, 1L); | |
| 357 | + private ProductSpuDO mockSpu(Long spuId) { | |
| 358 | + ProductSpuDO spu = randomPojo(ProductSpuDO.class, o -> o.setId(spuId)); | |
| 359 | + when(productSpuService.getSpu(eq(spuId), eq(true))).thenReturn(spu); | |
| 360 | + return spu; | |
| 361 | + } | |
| 190 | 362 | |
| 191 | - ProductCommentDO productCommentDO = productCommentMapper.selectById(productCommentId); | |
| 192 | - assertEquals("测试", productCommentDO.getReplyContent()); | |
| 363 | + @SafeVarargs | |
| 364 | + private static ProductCommentDO randomCommentDO(Consumer<ProductCommentDO>... consumers) { | |
| 365 | + Consumer<ProductCommentDO> consumer = (o) -> { | |
| 366 | + o.setScores(randomEle(ProductCommentScoresEnum.values()).getScores()); // 保证 scores 的范围 | |
| 367 | + o.setDescriptionScores(randomEle(ProductCommentScoresEnum.values()).getScores()); | |
| 368 | + o.setBenefitScores(randomEle(ProductCommentScoresEnum.values()).getScores()); | |
| 369 | + o.setSkuProperties(singletonList(new ProductSkuDO.Property(1L, "颜色", 2L, "红色"))); | |
| 370 | + }; | |
| 371 | + return randomPojo(ProductCommentDO.class, ArrayUtils.append(consumer, consumers)); | |
| 193 | 372 | } |
| 194 | 373 | |
| 195 | 374 | } | ... | ... |
yudao-module-mall/yudao-module-product/src/test/resources/sql/create_tables.sql
| ... | ... | @@ -126,32 +126,34 @@ CREATE TABLE IF NOT EXISTS `product_property_value` ( |
| 126 | 126 | PRIMARY KEY("id") |
| 127 | 127 | ) COMMENT '规格值'; |
| 128 | 128 | |
| 129 | -DROP TABLE IF EXISTS `product_comment` ( | |
| 130 | - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '评论编号,主键自增', | |
| 129 | +CREATE TABLE IF NOT EXISTS `product_comment` ( | |
| 130 | + `id` bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | |
| 131 | 131 | `user_id` bigint DEFAULT NULL COMMENT '评价人的用户编号关联 MemberUserDO 的 id 编号', |
| 132 | 132 | `user_nickname` varchar(255) DEFAULT NULL COMMENT '评价人名称', |
| 133 | - `user_avatar` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '评价人头像', | |
| 134 | - `anonymous` bit(1) DEFAULT NULL COMMENT '是否匿名', | |
| 133 | + `user_avatar` varchar(1024) DEFAULT NULL COMMENT '评价人头像', | |
| 134 | + `anonymous` bit DEFAULT NULL COMMENT '是否匿名', | |
| 135 | 135 | `order_id` bigint DEFAULT NULL COMMENT '交易订单编号关联 TradeOrderDO 的 id 编号', |
| 136 | 136 | `order_item_id` bigint DEFAULT NULL COMMENT '交易订单项编号关联 TradeOrderItemDO 的 id 编号', |
| 137 | 137 | `spu_id` bigint DEFAULT NULL COMMENT '商品 SPU 编号关联 ProductSpuDO 的 id', |
| 138 | 138 | `spu_name` varchar(255) DEFAULT NULL COMMENT '商品 SPU 名称', |
| 139 | 139 | `sku_id` bigint DEFAULT NULL COMMENT '商品 SKU 编号关联 ProductSkuDO 的 id 编号', |
| 140 | - `visible` bit(1) DEFAULT NULL COMMENT '是否可见true:显示false:隐藏', | |
| 140 | + `sku_pic_url` varchar(256) DEFAULT NULL COMMENT '商品 SKU 图片地址', | |
| 141 | + `sku_properties` varchar(512) DEFAULT NULL COMMENT '属性数组,JSON 格式', | |
| 142 | + `visible` bit DEFAULT NULL COMMENT '是否可见true:显示false:隐藏', | |
| 141 | 143 | `scores` tinyint DEFAULT NULL COMMENT '评分星级1-5分', |
| 142 | 144 | `description_scores` tinyint DEFAULT NULL COMMENT '描述星级1-5 星', |
| 143 | 145 | `benefit_scores` tinyint DEFAULT NULL COMMENT '服务星级1-5 星', |
| 144 | - `content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '评论内容', | |
| 146 | + `content` varchar(1024) DEFAULT NULL COMMENT '评论内容', | |
| 145 | 147 | `pic_urls` varchar(4096) DEFAULT NULL COMMENT '评论图片地址数组', |
| 146 | - `reply_status` bit(1) DEFAULT NULL COMMENT '商家是否回复', | |
| 148 | + `reply_status` bit DEFAULT NULL COMMENT '商家是否回复', | |
| 147 | 149 | `reply_user_id` bigint DEFAULT NULL COMMENT '回复管理员编号关联 AdminUserDO 的 id 编号', |
| 148 | - `reply_content` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商家回复内容', | |
| 149 | - `reply_time` datetime DEFAULT NULL COMMENT '商家回复时间', | |
| 150 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者', | |
| 151 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 152 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者', | |
| 153 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 154 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 155 | - `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', | |
| 156 | - PRIMARY KEY (`id`) USING BTREE | |
| 157 | -) ENGINE = InnoDB AUTO_INCREMENT = 26 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '商品评论'; | |
| 158 | 150 | \ No newline at end of file |
| 151 | + `reply_content` varchar(1024) DEFAULT NULL COMMENT '商家回复内容', | |
| 152 | + `reply_time` timestamp DEFAULT NULL COMMENT '商家回复时间', | |
| 153 | + "creator" varchar(64) DEFAULT '', | |
| 154 | + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| 155 | + "updater" varchar(64) DEFAULT '', | |
| 156 | + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| 157 | + "deleted" bit NOT NULL DEFAULT FALSE, | |
| 158 | + "tenant_id" bigint not null default '0', | |
| 159 | + PRIMARY KEY("id") | |
| 160 | +) COMMENT '商品评论'; | |
| 159 | 161 | \ No newline at end of file | ... | ... |