Commit 9d5d8c9527ca81c1a41633565d7cb62ee55d92c2

Authored by YunaiV
1 parent 6ed09714

fix(product): 修正虚拟评价创建契约并启用商品评价单测

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
... ...