Commit aea763e96eff6f838a77bce02c9c177ba903c377

Authored by luowenfeng
1 parent 31f5b27d

feature(单元测试): ProductSpuServiceImpl单元测试

sql/optional/mall/mall.sql
@@ -248,7 +248,7 @@ DROP TABLE IF EXISTS `product_spu`; @@ -248,7 +248,7 @@ DROP TABLE IF EXISTS `product_spu`;
248 CREATE TABLE `product_spu` ( 248 CREATE TABLE `product_spu` (
249 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', 249 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
250 `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号', 250 `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
251 - `brand_id` int DEFAULT NULL COMMENT '商品品牌编号', 251 + `brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号',
252 `category_id` bigint NOT NULL COMMENT '分类id', 252 `category_id` bigint NOT NULL COMMENT '分类id',
253 `spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格', 253 `spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
254 `code` varchar(128) DEFAULT NULL COMMENT '商品编码', 254 `code` varchar(128) DEFAULT NULL COMMENT '商品编码',
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/spu/ProductSpuStatusEnum.java
@@ -19,12 +19,12 @@ public enum ProductSpuStatusEnum implements IntArrayValuable { @@ -19,12 +19,12 @@ public enum ProductSpuStatusEnum implements IntArrayValuable {
19 DISABLE(0, "下架"), 19 DISABLE(0, "下架"),
20 ENABLE(1, "上架"),; 20 ENABLE(1, "上架"),;
21 21
22 - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStyle).toArray(); 22 + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ProductSpuStatusEnum::getStatus).toArray();
23 23
24 /** 24 /**
25 * 状态 25 * 状态
26 */ 26 */
27 - private final Integer style; 27 + private final Integer status;
28 /** 28 /**
29 * 状态名 29 * 状态名
30 */ 30 */
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/sku/ProductSkuDO.java
@@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO { @@ -97,6 +97,7 @@ public class ProductSkuDO extends BaseDO {
97 * 商品属性 97 * 商品属性
98 */ 98 */
99 @Data 99 @Data
  100 + @AllArgsConstructor
100 public static class Property { 101 public static class Property {
101 102
102 /** 103 /**
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
@@ -28,7 +28,10 @@ import org.springframework.transaction.annotation.Transactional; @@ -28,7 +28,10 @@ import org.springframework.transaction.annotation.Transactional;
28 import org.springframework.validation.annotation.Validated; 28 import org.springframework.validation.annotation.Validated;
29 29
30 import javax.annotation.Resource; 30 import javax.annotation.Resource;
31 -import java.util.*; 31 +import java.util.ArrayList;
  32 +import java.util.Collection;
  33 +import java.util.List;
  34 +import java.util.Map;
32 import java.util.stream.Collectors; 35 import java.util.stream.Collectors;
33 36
34 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 37 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -44,7 +47,7 @@ import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_E @@ -44,7 +47,7 @@ import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_E
44 public class ProductSpuServiceImpl implements ProductSpuService { 47 public class ProductSpuServiceImpl implements ProductSpuService {
45 48
46 @Resource 49 @Resource
47 - private ProductSpuMapper ProductSpuMapper; 50 + private ProductSpuMapper productSpuMapper;
48 51
49 @Resource 52 @Resource
50 private ProductCategoryService categoryService; 53 private ProductCategoryService categoryService;
@@ -77,7 +80,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -77,7 +80,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
77 spu.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); 80 spu.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
78 spu.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); 81 spu.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
79 spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); 82 spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
80 - ProductSpuMapper.insert(spu); 83 + productSpuMapper.insert(spu);
81 // 插入 SKU 84 // 插入 SKU
82 productSkuService.createSkus(spu.getId(), skuCreateReqList); 85 productSkuService.createSkus(spu.getId(), skuCreateReqList);
83 // 返回 86 // 返回
@@ -95,7 +98,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -95,7 +98,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
95 brandService.validateProductBrand(updateReqVO.getBrandId()); 98 brandService.validateProductBrand(updateReqVO.getBrandId());
96 // 校验SKU 99 // 校验SKU
97 List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus(); 100 List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
98 - // 多规格才需校验  
99 productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType()); 101 productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType());
100 102
101 // 更新 SPU 103 // 更新 SPU
@@ -104,7 +106,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -104,7 +106,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
104 updateObj.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); 106 updateObj.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
105 updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice)); 107 updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
106 updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum)); 108 updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
107 - ProductSpuMapper.updateById(updateObj); 109 + productSpuMapper.updateById(updateObj);
108 // 批量更新 SKU 110 // 批量更新 SKU
109 productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus()); 111 productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
110 } 112 }
@@ -115,13 +117,13 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -115,13 +117,13 @@ public class ProductSpuServiceImpl implements ProductSpuService {
115 // 校验存在 117 // 校验存在
116 validateSpuExists(id); 118 validateSpuExists(id);
117 // 删除 SPU 119 // 删除 SPU
118 - ProductSpuMapper.deleteById(id); 120 + productSpuMapper.deleteById(id);
119 // 删除关联的 SKU 121 // 删除关联的 SKU
120 productSkuService.deleteSkuBySpuId(id); 122 productSkuService.deleteSkuBySpuId(id);
121 } 123 }
122 124
123 private void validateSpuExists(Long id) { 125 private void validateSpuExists(Long id) {
124 - if (ProductSpuMapper.selectById(id) == null) { 126 + if (productSpuMapper.selectById(id) == null) {
125 throw exception(SPU_NOT_EXISTS); 127 throw exception(SPU_NOT_EXISTS);
126 } 128 }
127 } 129 }
@@ -129,7 +131,7 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -129,7 +131,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
129 @Override 131 @Override
130 // TODO @芋艿:需要再 review 下 132 // TODO @芋艿:需要再 review 下
131 public ProductSpuDetailRespVO getSpuDetail(Long id) { 133 public ProductSpuDetailRespVO getSpuDetail(Long id) {
132 - ProductSpuDO spu = ProductSpuMapper.selectById(id); 134 + ProductSpuDO spu = productSpuMapper.selectById(id);
133 ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class); 135 ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class);
134 if (null != spu) { 136 if (null != spu) {
135 List<ProductSpuDetailRespVO.Sku> skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id)); 137 List<ProductSpuDetailRespVO.Sku> skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id));
@@ -162,19 +164,6 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -162,19 +164,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
162 }); 164 });
163 respVO.setProductPropertyViews(productPropertyViews); 165 respVO.setProductPropertyViews(productPropertyViews);
164 } 166 }
165 - // 组合分类  
166 -// if (null != respVO.getCategoryId()) {  
167 -// LinkedList<Long> categoryArray = new LinkedList<>();  
168 -// Long parentId = respVO.getCategoryId();  
169 -// categoryArray.addFirst(parentId);  
170 -// while (parentId != 0) {  
171 -// parentId = categoryService.getCategory(parentId).getParentId();  
172 -// if (parentId > 0) {  
173 -// categoryArray.addFirst(parentId);  
174 -// }  
175 -// }  
176 -//  
177 -// }  
178 respVO.setCategoryIds(respVO.getCategoryId()); 167 respVO.setCategoryIds(respVO.getCategoryId());
179 } 168 }
180 return respVO; 169 return respVO;
@@ -182,12 +171,12 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -182,12 +171,12 @@ public class ProductSpuServiceImpl implements ProductSpuService {
182 171
183 @Override 172 @Override
184 public ProductSpuRespVO getSpu(Long id) { 173 public ProductSpuRespVO getSpu(Long id) {
185 - return ProductSpuConvert.INSTANCE.convert(ProductSpuMapper.selectById(id)); 174 + return ProductSpuConvert.INSTANCE.convert(productSpuMapper.selectById(id));
186 } 175 }
187 176
188 @Override 177 @Override
189 public List<ProductSpuDO> getSpuList(Collection<Long> ids) { 178 public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
190 - return ProductSpuMapper.selectBatchIds(ids); 179 + return productSpuMapper.selectBatchIds(ids);
191 } 180 }
192 181
193 @Override 182 @Override
@@ -199,13 +188,14 @@ public class ProductSpuServiceImpl implements ProductSpuService { @@ -199,13 +188,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
199 remindSpuIds.add(null); 188 remindSpuIds.add(null);
200 } 189 }
201 } 190 }
202 - return ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO, remindSpuIds)); 191 + return ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(pageReqVO, remindSpuIds));
203 } 192 }
204 193
205 @Override 194 @Override
206 public PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO) { 195 public PageResult<AppSpuPageRespVO> getSpuPage(AppSpuPageReqVO pageReqVO) {
207 - PageResult<ProductSpuDO> productSpuDOPageResult = ProductSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO)); 196 + PageResult<ProductSpuDO> productSpuDOPageResult = productSpuMapper.selectPage(ProductSpuConvert.INSTANCE.convert(pageReqVO));
208 PageResult<AppSpuPageRespVO> pageResult = new PageResult<>(); 197 PageResult<AppSpuPageRespVO> pageResult = new PageResult<>();
  198 + // TODO @芋艿 这里用convert如何解决
209 List<AppSpuPageRespVO> collect = productSpuDOPageResult.getList() 199 List<AppSpuPageRespVO> collect = productSpuDOPageResult.getList()
210 .stream() 200 .stream()
211 .map(ProductSpuConvert.INSTANCE::convertAppResp) 201 .map(ProductSpuConvert.INSTANCE::convertAppResp)
yudao-module-mall/yudao-module-product-biz/src/test/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImplTest.java
1 package cn.iocoder.yudao.module.product.service.spu; 1 package cn.iocoder.yudao.module.product.service.spu;
2 2
  3 +import cn.iocoder.yudao.framework.common.exception.ServiceException;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
5 -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuCreateReqVO;  
6 -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;  
7 -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuRespVO;  
8 -import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateReqVO; 7 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
  8 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
  9 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
  10 +import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
  11 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO;
  13 +import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
  14 +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
9 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; 15 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
10 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; 16 import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
11 -import org.junit.jupiter.api.Disabled; 17 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
  18 +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
  19 +import cn.iocoder.yudao.module.product.service.brand.ProductBrandServiceImpl;
  20 +import cn.iocoder.yudao.module.product.service.category.ProductCategoryServiceImpl;
  21 +import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
  22 +import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
  23 +import cn.iocoder.yudao.module.product.service.sku.ProductSkuServiceImpl;
  24 +import com.google.common.collect.Lists;
  25 +import org.junit.jupiter.api.Assertions;
12 import org.junit.jupiter.api.Test; 26 import org.junit.jupiter.api.Test;
  27 +import org.mockito.Mockito;
  28 +import org.springframework.boot.test.mock.mockito.MockBean;
13 import org.springframework.context.annotation.Import; 29 import org.springframework.context.annotation.Import;
14 30
15 import javax.annotation.Resource; 31 import javax.annotation.Resource;
  32 +import java.util.ArrayList;
  33 +import java.util.List;
  34 +import java.util.Map;
  35 +import java.util.stream.Collectors;
  36 +import java.util.stream.Stream;
16 37
17 -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;  
18 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; 38 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
19 -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;  
20 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 39 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
21 -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_EXISTS;  
22 -import static org.junit.jupiter.api.Assertions.*;  
23 40
24 /** 41 /**
25 -* {@link ProductSpuServiceImpl} 的单元测试类  
26 -*  
27 -* @author 芋道源码  
28 -*/ 42 + * {@link ProductSpuServiceImpl} 的单元测试类
  43 + *
  44 + * @author 芋道源码
  45 + */
29 @Import(ProductSpuServiceImpl.class) 46 @Import(ProductSpuServiceImpl.class)
30 public class ProductSpuServiceImplTest extends BaseDbUnitTest { 47 public class ProductSpuServiceImplTest extends BaseDbUnitTest {
31 48
32 @Resource 49 @Resource
33 - private ProductSpuServiceImpl spuService; 50 + private ProductSpuServiceImpl productSpuService;
34 51
35 @Resource 52 @Resource
36 - private ProductSpuMapper ProductSpuMapper; 53 + private ProductSpuMapper productSpuMapper;
  54 +
  55 +
  56 + @MockBean
  57 + private ProductSkuServiceImpl productSkuService;
  58 +
  59 + @MockBean
  60 + private ProductCategoryServiceImpl categoryService;
  61 +
  62 + @MockBean
  63 + private ProductBrandServiceImpl brandService;
  64 +
  65 + @MockBean
  66 + private ProductPropertyService productPropertyService;
  67 +
  68 + @MockBean
  69 + private ProductPropertyValueService productPropertyValueService;
  70 +
37 71
38 @Test 72 @Test
39 public void testCreateSpu_success() { 73 public void testCreateSpu_success() {
40 // 准备参数 74 // 准备参数
41 - ProductSpuCreateReqVO reqVO = randomPojo(ProductSpuCreateReqVO.class); 75 + ProductSpuCreateReqVO createReqVO = randomPojo(ProductSpuCreateReqVO.class, o -> {
  76 + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType());
  77 + o.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
  78 + });
  79 +
  80 + // 校验SKU
  81 + List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
  82 +
  83 + Long spu = productSpuService.createSpu(createReqVO);
  84 + ProductSpuDO productSpuDO = productSpuMapper.selectById(spu);
  85 +
  86 + createReqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
  87 + createReqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
  88 + createReqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
  89 + createReqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
  90 +
  91 + assertPojoEquals(createReqVO, productSpuDO);
42 92
43 - // 调用  
44 - Long spuId = spuService.createSpu(reqVO);  
45 - // 断言  
46 - assertNotNull(spuId);  
47 - // 校验记录的属性是否正确  
48 - ProductSpuDO spu = ProductSpuMapper.selectById(spuId);  
49 - assertPojoEquals(reqVO, spu);  
50 } 93 }
51 94
52 @Test 95 @Test
53 public void testUpdateSpu_success() { 96 public void testUpdateSpu_success() {
54 - // mock 数据  
55 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class);  
56 - ProductSpuMapper.insert(dbSpu);// @Sql: 先插入出一条存在的数据 97 + // 准备参数
  98 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class);
  99 + productSpuMapper.insert(createReqVO);
57 // 准备参数 100 // 准备参数
58 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> { 101 ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
59 - o.setId(dbSpu.getId()); // 设置更新的 ID 102 + o.setId(createReqVO.getId()); // 设置更新的 ID
  103 + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType());
  104 + o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
60 }); 105 });
61 -  
62 // 调用 106 // 调用
63 - spuService.updateSpu(reqVO); 107 + productSpuService.updateSpu(reqVO);
  108 +
  109 + List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = reqVO.getSkus();
  110 + reqVO.setMarketPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getMarketPrice));
  111 + reqVO.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
  112 + reqVO.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
  113 + reqVO.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
  114 +
64 // 校验是否更新正确 115 // 校验是否更新正确
65 - ProductSpuDO spu = ProductSpuMapper.selectById(reqVO.getId()); // 获取最新的 116 + ProductSpuDO spu = productSpuMapper.selectById(reqVO.getId()); // 获取最新的
66 assertPojoEquals(reqVO, spu); 117 assertPojoEquals(reqVO, spu);
67 } 118 }
68 119
69 @Test 120 @Test
70 - public void testUpdateSpu_notExists() { 121 + public void testValidateSpuExists_exception() {
  122 + ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class, o -> {
  123 + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType());
  124 + o.setStatus(ProductSpuStatusEnum.DISABLE.getStatus());
  125 + });
  126 + // 调用
  127 + Assertions.assertThrows(ServiceException.class, () -> productSpuService.updateSpu(reqVO));
  128 + }
  129 +
  130 + @Test
  131 + void deleteSpu() {
  132 + // 准备参数
  133 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class);
  134 + productSpuMapper.insert(createReqVO);
  135 +
  136 + // 调用
  137 + productSpuService.deleteSpu(createReqVO.getId());
  138 +
  139 + Assertions.assertNull(productSpuMapper.selectById(createReqVO.getId()));
  140 + }
  141 +
  142 + @Test
  143 + void getSpuDetail() {
  144 + // 准备spu参数
  145 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> {
  146 + o.setSpecType(ProductSpuSpecTypeEnum.DISABLE.getType());
  147 + });
  148 + productSpuMapper.insert(createReqVO);
  149 +
  150 + // 创建两个属性
  151 + ArrayList<ProductPropertyRespVO> productPropertyRespVOS = Lists.newArrayList(
  152 + randomPojo(ProductPropertyRespVO.class),
  153 + randomPojo(ProductPropertyRespVO.class));
  154 +
  155 + // 所有属性值
  156 + ArrayList<ProductPropertyValueRespVO> productPropertyValueRespVO = new ArrayList<>();
  157 +
  158 + // 每个属性创建属性值
  159 + productPropertyRespVOS.forEach(v -> {
  160 + ProductPropertyValueRespVO productPropertyValueRespVO1 = randomPojo(ProductPropertyValueRespVO.class, o -> o.setPropertyId(v.getId()));
  161 + productPropertyValueRespVO.add(productPropertyValueRespVO1);
  162 + });
  163 +
  164 + // 属性值建立笛卡尔积
  165 + Map<Long, List<ProductPropertyValueRespVO>> collect = productPropertyValueRespVO.stream().collect(Collectors.groupingBy(ProductPropertyValueRespVO::getPropertyId));
  166 + List<List<ProductPropertyValueRespVO>> lists = cartesianProduct(Lists.newArrayList(collect.values()));
  167 +
  168 + // 准备sku参数
  169 + ArrayList<ProductSkuDO> productSkuDOS = Lists.newArrayList();
  170 + lists.forEach(pp -> {
  171 + List<ProductSkuDO.Property> property = pp.stream().map(ppv -> new ProductSkuDO.Property(ppv.getPropertyId(), ppv.getId())).collect(Collectors.toList());
  172 + ProductSkuDO productSkuDO = randomPojo(ProductSkuDO.class, o -> {
  173 + o.setProperties(property);
  174 + });
  175 + productSkuDOS.add(productSkuDO);
  176 +
  177 + });
  178 +
  179 + Mockito.when(productSkuService.getSkusBySpuId(createReqVO.getId())).thenReturn(productSkuDOS);
  180 + Mockito.when(productPropertyValueService.getPropertyValueListByPropertyId(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyValueRespVO);
  181 + Mockito.when(productPropertyService.getPropertyList(new ArrayList<>(collect.keySet()))).thenReturn(productPropertyRespVOS);
  182 +
  183 + // 调用
  184 + ProductSpuDetailRespVO spuDetail = productSpuService.getSpuDetail(createReqVO.getId());
  185 +
  186 + assertPojoEquals(createReqVO, spuDetail);
  187 + }
  188 +
  189 + @Test
  190 + void getSpu() {
71 // 准备参数 191 // 准备参数
72 - ProductSpuUpdateReqVO reqVO = randomPojo(ProductSpuUpdateReqVO.class); 192 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class);
  193 + productSpuMapper.insert(createReqVO);
73 194
74 - // 调用, 并断言异常  
75 - assertServiceException(() -> spuService.updateSpu(reqVO), SPU_NOT_EXISTS); 195 + ProductSpuRespVO spu = productSpuService.getSpu(createReqVO.getId());
  196 + assertPojoEquals(createReqVO, spu);
76 } 197 }
77 198
78 @Test 199 @Test
79 - public void testDeleteSpu_success() {  
80 - // mock 数据  
81 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class);  
82 - ProductSpuMapper.insert(dbSpu);// @Sql: 先插入出一条存在的数据 200 + void getSpuList() {
83 // 准备参数 201 // 准备参数
84 - Long id = dbSpu.getId(); 202 + ArrayList<ProductSpuDO> createReqVO = Lists.newArrayList(randomPojo(ProductSpuDO.class), randomPojo(ProductSpuDO.class));
  203 + productSpuMapper.insertBatch(createReqVO);
85 204
86 // 调用 205 // 调用
87 - spuService.deleteSpu(id);  
88 - // 校验数据不存在了  
89 - assertNull(ProductSpuMapper.selectById(id)); 206 + List<ProductSpuDO> spuList = productSpuService.getSpuList(createReqVO.stream().map(ProductSpuDO::getId).collect(Collectors.toList()));
  207 + Assertions.assertIterableEquals(createReqVO, spuList);
90 } 208 }
91 209
92 @Test 210 @Test
93 - public void testDeleteSpu_notExists() { 211 + void getSpuPage() {
94 // 准备参数 212 // 准备参数
95 - Long id = 1L; 213 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class);
  214 + productSpuMapper.insert(createReqVO);
  215 +
  216 + ArrayList<ProductSkuDO> remindSpuIds = Lists.newArrayList(
  217 +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())),
  218 +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId()))
  219 + );
96 220
97 - // 调用, 并断言异常  
98 - assertServiceException(() -> spuService.deleteSpu(id), SPU_NOT_EXISTS); 221 + Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds);
  222 +
  223 + // 调用
  224 + ProductSpuPageReqVO productSpuPageReqVO = new ProductSpuPageReqVO();
  225 + productSpuPageReqVO.setTabStatus(2);
  226 +
  227 + PageResult<ProductSpuRespVO> spuPage = productSpuService.getSpuPage(productSpuPageReqVO);
  228 +
  229 + ArrayList<Long> resultRemindSpuIds = new ArrayList<>();
  230 + resultRemindSpuIds.add(null);
  231 + PageResult<ProductSpuRespVO> result = ProductSpuConvert.INSTANCE.convertPage(productSpuMapper.selectPage(productSpuPageReqVO, resultRemindSpuIds));
  232 + Assertions.assertIterableEquals(result.getList(), spuPage.getList());
  233 + Assertions.assertEquals(spuPage.getTotal(), result.getTotal());
99 } 234 }
100 235
101 @Test 236 @Test
102 - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解  
103 - public void testGetSpuPage() {  
104 - // mock 数据  
105 - ProductSpuDO dbSpu = randomPojo(ProductSpuDO.class, o -> { // 等会查询到  
106 - o.setName(null);  
107 - o.setSellPoint(null);  
108 - o.setDescription(null);  
109 - o.setCategoryId(null);  
110 - o.setPicUrls(null);  
111 - o.setSort(null);  
112 -// o.setLikeCount(null);  
113 -// o.setPrice(null);  
114 -// o.setQuantity(null);  
115 - o.setStatus(null);  
116 - o.setCreateTime(null);  
117 - });  
118 - ProductSpuMapper.insert(dbSpu);  
119 - // 测试 name 不匹配  
120 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setName(null)));  
121 - // 测试 sellPoint 不匹配  
122 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setSellPoint(null)));  
123 - // 测试 description 不匹配  
124 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setDescription(null)));  
125 - // 测试 categoryId 不匹配  
126 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setCategoryId(null)));  
127 - // 测试 picUrls 不匹配  
128 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setPicUrls(null)));  
129 - // 测试 sort 不匹配  
130 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setSort(null)));  
131 - // 测试 likeCount 不匹配  
132 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setLikeCount(null)));  
133 - // 测试 price 不匹配  
134 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setPrice(null)));  
135 - // 测试 quantity 不匹配  
136 -// ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setQuantity(null)));  
137 - // 测试 status 不匹配  
138 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setStatus(null)));  
139 - // 测试 createTime 不匹配  
140 - ProductSpuMapper.insert(cloneIgnoreId(dbSpu, o -> o.setCreateTime(null)));  
141 - // 准备参数  
142 - ProductSpuPageReqVO reqVO = new ProductSpuPageReqVO();  
143 - reqVO.setName(null);  
144 - reqVO.setSellPoint(null);  
145 - reqVO.setDescription(null);  
146 - reqVO.setCategoryId(null);  
147 - reqVO.setPicUrls(null);  
148 - reqVO.setSort(null);  
149 - reqVO.setLikeCount(null);  
150 - reqVO.setPrice(null);  
151 - reqVO.setQuantity(null);  
152 - reqVO.setStatus(null);  
153 - reqVO.setCreateTime(null);  
154 -  
155 - // 调用  
156 - PageResult<ProductSpuRespVO> pageResult = spuService.getSpuPage(reqVO);  
157 - // 断言  
158 - assertEquals(1, pageResult.getTotal());  
159 - assertEquals(1, pageResult.getList().size());  
160 - assertPojoEquals(dbSpu, pageResult.getList().get(0)); 237 + void testGetSpuPage() {
  238 +// 准备参数
  239 + ProductSpuDO createReqVO = randomPojo(ProductSpuDO.class, o -> {
  240 + o.setCategoryId(2L);
  241 + });
  242 + productSpuMapper.insert(createReqVO);
  243 +
  244 + ArrayList<ProductSkuDO> remindSpuIds = Lists.newArrayList(
  245 +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId())),
  246 +// randomPojo(ProductSkuDO.class, o -> o.setSpuId(createReqVO.getId()))
  247 + );
  248 +
  249 + Mockito.when(productSkuService.getRemindSpuIds()).thenReturn(remindSpuIds);
  250 +
  251 + // 调用
  252 + AppSpuPageReqVO appSpuPageReqVO = new AppSpuPageReqVO();
  253 + appSpuPageReqVO.setCategoryId(2L);
  254 +
  255 + PageResult<AppSpuPageRespVO> spuPage = productSpuService.getSpuPage(appSpuPageReqVO);
  256 +
  257 + PageResult<ProductSpuDO> result = productSpuMapper.selectPage(
  258 + ProductSpuConvert.INSTANCE.convert(appSpuPageReqVO));
  259 +
  260 + List<AppSpuPageRespVO> collect = result.getList()
  261 + .stream()
  262 + .map(ProductSpuConvert.INSTANCE::convertAppResp)
  263 + .collect(Collectors.toList());
  264 +
  265 + Assertions.assertIterableEquals(collect, spuPage.getList());
  266 + Assertions.assertEquals(spuPage.getTotal(), result.getTotal());
  267 + }
  268 +
  269 +
  270 + /**
  271 + * 生成笛卡尔积
  272 + *
  273 + * @param data 数据
  274 + * @return 笛卡尔积
  275 + */
  276 + public static <T> List<List<T>> cartesianProduct(List<List<T>> data) {
  277 + List<List<T>> res = null; // 结果集(当前为第N个List,则该处存放的就为前N-1个List的笛卡尔积集合)
  278 + for (List<T> list : data) { // 遍历数据
  279 + List<List<T>> temp = new ArrayList<>(); // 临时结果集,存放本次循环后生成的笛卡尔积集合
  280 + if (res == null) { // 结果集为null表示第一次循环既list为第一个List
  281 + for (T t : list) { // 便利第一个List
  282 + // 利用stream生成List,第一个List的笛卡尔积集合约等于自己本身(需要创建一个List并把对象添加到当中),存放到临时结果集
  283 + temp.add(Stream.of(t).collect(Collectors.toList()));
  284 + }
  285 + res = temp; // 将临时结果集赋值给结果集
  286 + continue; // 跳过本次循环
  287 + }
  288 + // 不为第一个List,计算前面的集合(笛卡尔积)和当前List的笛卡尔积集合
  289 + for (T t : list) { // 便利
  290 + for (List<T> rl : res) { // 便利前面的笛卡尔积集合
  291 + // 利用stream生成List
  292 + temp.add(Stream.concat(rl.stream(), Stream.of(t)).collect(Collectors.toList()));
  293 + }
  294 + }
  295 + res = temp; // 将临时结果集赋值给结果集
  296 + }
  297 + // 返回结果
  298 + return res;
161 } 299 }
162 300
163 } 301 }
yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/clean.sql
1 -DELETE FROM "product_category"; 1 +DELETE FROM "product_sku";
2 2
3 -DELETE FROM "product_brand";  
4 \ No newline at end of file 3 \ No newline at end of file
  4 +DELETE FROM "product_spu";
5 \ No newline at end of file 5 \ No newline at end of file
yudao-module-mall/yudao-module-product-biz/src/test/resources/sql/create_tables.sql
1 -CREATE TABLE IF NOT EXISTS "product_category" (  
2 - "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,  
3 - "parent_id" bigint(20) NOT NULL,  
4 - "name" varchar(255) NOT NULL,  
5 - "pic_url" varchar(255) NOT NULL,  
6 - "sort" int(11) NOT NULL,  
7 - "description" varchar(1024) NOT NULL,  
8 - "status" tinyint(4) NOT NULL,  
9 - "creator" varchar(64) DEFAULT '',  
10 - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
11 - "updater" varchar(64) DEFAULT '',  
12 - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
13 - "deleted" bit NOT NULL DEFAULT FALSE,  
14 - PRIMARY KEY ("id")  
15 -) COMMENT '商品分类'; 1 +CREATE TABLE IF NOT EXISTS `product_sku` (
  2 +`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  3 +`spu_id` bigint NOT NULL COMMENT 'spu编号',
  4 +`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  5 +`name` varchar(128) DEFAULT NULL COMMENT '商品 SKU 名字',
  6 +`properties` varchar(128) DEFAULT NULL COMMENT '规格值数组-json格式, [{propertId: , valueId: }, {propertId: , valueId: }]',
  7 +`price` int NOT NULL DEFAULT '-1' COMMENT '销售价格,单位:分',
  8 +`market_price` int DEFAULT NULL COMMENT '市场价',
  9 +`cost_price` int NOT NULL DEFAULT '-1' COMMENT '成本价,单位: 分',
  10 +`pic_url` varchar(128) NOT NULL COMMENT '图片地址',
  11 +`stock` int DEFAULT NULL COMMENT '库存',
  12 +`warn_stock` int DEFAULT NULL COMMENT '预警库存',
  13 +`volume` double DEFAULT NULL COMMENT '商品体积',
  14 +`weight` double DEFAULT NULL COMMENT '商品重量',
  15 +`bar_code` varchar(64) DEFAULT NULL COMMENT '条形码',
  16 +`status` tinyint DEFAULT NULL COMMENT '状态: 0-正常 1-禁用',
  17 +`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  18 +`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  19 +`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
  20 +`updater` double DEFAULT NULL COMMENT '更新人',
  21 +`deleted` bit(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
  22 +PRIMARY KEY (`id`)
  23 +) COMMENT '商品sku';
16 24
17 -CREATE TABLE IF NOT EXISTS "product_brand" (  
18 - "id" bigint(20) NOT NULL GENERATED BY DEFAULT AS IDENTITY,  
19 - "name" varchar(255) NOT NULL,  
20 - "pic_url" varchar(255) NOT NULL,  
21 - "sort" int(11),  
22 - "description" varchar(1024),  
23 - "status" tinyint(4) NOT NULL,  
24 - "creator" varchar(64) DEFAULT '',  
25 - "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,  
26 - "updater" varchar(64) DEFAULT '',  
27 - "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  
28 - "deleted" bit NOT NULL DEFAULT FALSE,  
29 - PRIMARY KEY ("id")  
30 -) COMMENT '商品品牌'; 25 +
  26 +CREATE TABLE IF NOT EXISTS `product_spu` (
  27 +`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  28 +`tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
  29 +`brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号',
  30 +`category_id` bigint NOT NULL COMMENT '分类id',
  31 +`spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
  32 +`code` varchar(128) DEFAULT NULL COMMENT '商品编码',
  33 +`name` varchar(128) NOT NULL COMMENT '商品名称',
  34 +`sell_point` varchar(128) DEFAULT NULL COMMENT '卖点',
  35 +`description` text COMMENT '描述',
  36 +`pic_urls` varchar(1024) DEFAULT '' COMMENT '商品轮播图地址数组,以逗号分隔最多上传15张',
  37 +`video_url` varchar(128) DEFAULT NULL COMMENT '商品视频',
  38 +`market_price` int DEFAULT NULL COMMENT '市场价,单位使用:分',
  39 +`min_price` int DEFAULT NULL COMMENT '最小价格,单位使用:分',
  40 +`max_price` int DEFAULT NULL COMMENT '最大价格,单位使用:分',
  41 +`total_stock` int NOT NULL DEFAULT '0' COMMENT '总库存',
  42 +`show_stock` int DEFAULT '0' COMMENT '是否展示库存',
  43 +`sales_count` int DEFAULT '0' COMMENT '商品销量',
  44 +`virtual_sales_count` int DEFAULT '0' COMMENT '虚拟销量',
  45 +`click_count` int DEFAULT '0' COMMENT '商品点击量',
  46 +`status` bit(1) DEFAULT NULL COMMENT '上下架状态: 0 上架(开启) 1 下架(禁用)-1 回收',
  47 +`sort` int NOT NULL DEFAULT '0' COMMENT '排序字段',
  48 +`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  49 +`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  50 +`creator` varchar(64) DEFAULT NULL COMMENT '创建人',
  51 +`updater` varchar(64) DEFAULT NULL COMMENT '更新人',
  52 +`deleted` bit(1) NOT NULL DEFAULT 0 COMMENT '是否删除',
  53 +PRIMARY KEY (`id`)
  54 +) COMMENT '商品spu';