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 248 CREATE TABLE `product_spu` (
249 249 `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
250 250 `tenant_id` bigint NOT NULL DEFAULT '0' COMMENT '租户编号',
251   - `brand_id` int DEFAULT NULL COMMENT '商品品牌编号',
  251 + `brand_id` bigint DEFAULT NULL COMMENT '商品品牌编号',
252 252 `category_id` bigint NOT NULL COMMENT '分类id',
253 253 `spec_type` int NOT NULL COMMENT '规格类型:0 单规格 1 多规格',
254 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 19 DISABLE(0, "下架"),
20 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 97 * 商品属性
98 98 */
99 99 @Data
  100 + @AllArgsConstructor
100 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 28 import org.springframework.validation.annotation.Validated;
29 29  
30 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 35 import java.util.stream.Collectors;
33 36  
34 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 47 public class ProductSpuServiceImpl implements ProductSpuService {
45 48  
46 49 @Resource
47   - private ProductSpuMapper ProductSpuMapper;
  50 + private ProductSpuMapper productSpuMapper;
48 51  
49 52 @Resource
50 53 private ProductCategoryService categoryService;
... ... @@ -77,7 +80,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
77 80 spu.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
78 81 spu.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
79 82 spu.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
80   - ProductSpuMapper.insert(spu);
  83 + productSpuMapper.insert(spu);
81 84 // 插入 SKU
82 85 productSkuService.createSkus(spu.getId(), skuCreateReqList);
83 86 // 返回
... ... @@ -95,7 +98,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
95 98 brandService.validateProductBrand(updateReqVO.getBrandId());
96 99 // 校验SKU
97 100 List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
98   - // 多规格才需校验
99 101 productSkuService.validateSkus(skuCreateReqList, updateReqVO.getSpecType());
100 102  
101 103 // 更新 SPU
... ... @@ -104,7 +106,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
104 106 updateObj.setMaxPrice(CollectionUtils.getMaxValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
105 107 updateObj.setMinPrice(CollectionUtils.getMinValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getPrice));
106 108 updateObj.setTotalStock(CollectionUtils.getSumValue(skuCreateReqList, ProductSkuCreateOrUpdateReqVO::getStock, Integer::sum));
107   - ProductSpuMapper.updateById(updateObj);
  109 + productSpuMapper.updateById(updateObj);
108 110 // 批量更新 SKU
109 111 productSkuService.updateProductSkus(updateObj.getId(), updateReqVO.getSkus());
110 112 }
... ... @@ -115,13 +117,13 @@ public class ProductSpuServiceImpl implements ProductSpuService {
115 117 // 校验存在
116 118 validateSpuExists(id);
117 119 // 删除 SPU
118   - ProductSpuMapper.deleteById(id);
  120 + productSpuMapper.deleteById(id);
119 121 // 删除关联的 SKU
120 122 productSkuService.deleteSkuBySpuId(id);
121 123 }
122 124  
123 125 private void validateSpuExists(Long id) {
124   - if (ProductSpuMapper.selectById(id) == null) {
  126 + if (productSpuMapper.selectById(id) == null) {
125 127 throw exception(SPU_NOT_EXISTS);
126 128 }
127 129 }
... ... @@ -129,7 +131,7 @@ public class ProductSpuServiceImpl implements ProductSpuService {
129 131 @Override
130 132 // TODO @芋艿:需要再 review 下
131 133 public ProductSpuDetailRespVO getSpuDetail(Long id) {
132   - ProductSpuDO spu = ProductSpuMapper.selectById(id);
  134 + ProductSpuDO spu = productSpuMapper.selectById(id);
133 135 ProductSpuDetailRespVO respVO = BeanUtil.copyProperties(spu, ProductSpuDetailRespVO.class);
134 136 if (null != spu) {
135 137 List<ProductSpuDetailRespVO.Sku> skuReqs = ProductSkuConvert.INSTANCE.convertList03(productSkuService.getSkusBySpuId(id));
... ... @@ -162,19 +164,6 @@ public class ProductSpuServiceImpl implements ProductSpuService {
162 164 });
163 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 167 respVO.setCategoryIds(respVO.getCategoryId());
179 168 }
180 169 return respVO;
... ... @@ -182,12 +171,12 @@ public class ProductSpuServiceImpl implements ProductSpuService {
182 171  
183 172 @Override
184 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 177 @Override
189 178 public List<ProductSpuDO> getSpuList(Collection<Long> ids) {
190   - return ProductSpuMapper.selectBatchIds(ids);
  179 + return productSpuMapper.selectBatchIds(ids);
191 180 }
192 181  
193 182 @Override
... ... @@ -199,13 +188,14 @@ public class ProductSpuServiceImpl implements ProductSpuService {
199 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 194 @Override
206 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 197 PageResult<AppSpuPageRespVO> pageResult = new PageResult<>();
  198 + // TODO @芋艿 这里用convert如何解决
209 199 List<AppSpuPageRespVO> collect = productSpuDOPageResult.getList()
210 200 .stream()
211 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 1 package cn.iocoder.yudao.module.product.service.spu;
2 2  
  3 +import cn.iocoder.yudao.framework.common.exception.ServiceException;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
4 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 15 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
10 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 26 import org.junit.jupiter.api.Test;
  27 +import org.mockito.Mockito;
  28 +import org.springframework.boot.test.mock.mockito.MockBean;
13 29 import org.springframework.context.annotation.Import;
14 30  
15 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 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 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 46 @Import(ProductSpuServiceImpl.class)
30 47 public class ProductSpuServiceImplTest extends BaseDbUnitTest {
31 48  
32 49 @Resource
33   - private ProductSpuServiceImpl spuService;
  50 + private ProductSpuServiceImpl productSpuService;
34 51  
35 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 72 @Test
39 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 95 @Test
53 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 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 117 assertPojoEquals(reqVO, spu);
67 118 }
68 119  
69 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 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 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 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 3 \ No newline at end of file
  4 +DELETE FROM "product_spu";
5 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';
... ...