test: 使用 H2 验证可用库存查询
This commit is contained in:
@@ -129,6 +129,18 @@
|
||||
<groupId>cn.nl.cloud</groupId>
|
||||
<artifactId>nl-spring-boot-starter-monitor</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package cn.code.nl.module.wms.dal.mysql.iostorinvdtl;
|
||||
|
||||
import cn.code.nl.framework.common.pojo.PageResult;
|
||||
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryPageReqVO;
|
||||
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryRespVO;
|
||||
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.ExpandAvailableInventoryReqVO;
|
||||
import cn.code.nl.module.wms.service.iostorinv.IostorInvServiceImpl;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.jdbc.Sql;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import jakarta.annotation.Resource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@SpringJUnitConfig
|
||||
@ContextConfiguration(classes = IostorinvDtlMapperTest.TestConfiguration.class)
|
||||
@Sql("/sql/iostorinv/available-inventory.sql")
|
||||
@Transactional
|
||||
class IostorinvDtlMapperTest {
|
||||
|
||||
@Resource
|
||||
private IostorinvDtlMapper mapper;
|
||||
|
||||
@Test
|
||||
void shouldExpandAvailableChildrenAndExecutePageFilters() throws Exception {
|
||||
IostorInvServiceImpl service = new IostorInvServiceImpl();
|
||||
Field mapperField = IostorInvServiceImpl.class.getDeclaredField("iostorinvDtlMapper");
|
||||
mapperField.setAccessible(true);
|
||||
mapperField.set(service, mapper);
|
||||
|
||||
ExpandAvailableInventoryReqVO expandReqVO = new ExpandAvailableInventoryReqVO();
|
||||
expandReqVO.setStorId("STOR-001");
|
||||
expandReqVO.setVehicleCodes(List.of("BOX-001", "BOX-001"));
|
||||
List<AvailableInventoryRespVO> expanded = service.expandAvailableInventory(expandReqVO);
|
||||
|
||||
assertEquals(2, expanded.size());
|
||||
assertTrue(expanded.stream().allMatch(item -> "BOX-001".equals(item.getVehicleCode())));
|
||||
assertTrue(expanded.stream().allMatch(item -> "STOR-001".equals(item.getStorId())));
|
||||
assertEquals(2, expanded.stream().map(AvailableInventoryRespVO::getPcsn).distinct().count());
|
||||
assertTrue(expanded.stream().allMatch(item -> item.getAvailableQty().signum() > 0));
|
||||
|
||||
AvailableInventoryPageReqVO warehousePageReqVO = new AvailableInventoryPageReqVO();
|
||||
warehousePageReqVO.setStorId("STOR-001");
|
||||
warehousePageReqVO.setPageNo(1);
|
||||
warehousePageReqVO.setPageSize(10);
|
||||
PageResult<AvailableInventoryRespVO> warehousePage = mapper.selectAvailableInventoryPage(warehousePageReqVO);
|
||||
assertEquals(2L, warehousePage.getTotal());
|
||||
|
||||
AvailableInventoryPageReqVO pageReqVO = new AvailableInventoryPageReqVO();
|
||||
pageReqVO.setStorId("STOR-001");
|
||||
pageReqVO.setMaterialCode("MAT-001");
|
||||
pageReqVO.setVehicleCode("BOX-001");
|
||||
pageReqVO.setPcsn("PCSN-002");
|
||||
pageReqVO.setPageNo(1);
|
||||
pageReqVO.setPageSize(10);
|
||||
PageResult<AvailableInventoryRespVO> page = mapper.selectAvailableInventoryPage(pageReqVO);
|
||||
|
||||
assertEquals(1L, page.getTotal());
|
||||
assertEquals("PCSN-002", page.getList().get(0).getPcsn());
|
||||
assertEquals("材料一", page.getList().get(0).getMaterialName());
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@MapperScan(basePackageClasses = IostorinvDtlMapper.class)
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
DataSource dataSource() {
|
||||
return new DriverManagerDataSource("jdbc:h2:mem:available_inventory;MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", "");
|
||||
}
|
||||
|
||||
@Bean
|
||||
SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
|
||||
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
|
||||
factory.setDataSource(dataSource);
|
||||
factory.setMapperLocations(new org.springframework.core.io.ClassPathResource(
|
||||
"mapper/iostorinvdtl/IostorinvDtlMapper.xml"));
|
||||
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
|
||||
configuration.setMapUnderscoreToCamelCase(true);
|
||||
factory.setConfiguration(configuration);
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
|
||||
factory.setPlugins(interceptor);
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
@Bean
|
||||
PlatformTransactionManager transactionManager(DataSource dataSource) {
|
||||
return new DataSourceTransactionManager(dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package cn.code.nl.module.wms.service.iostorinv;
|
||||
|
||||
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryRespVO;
|
||||
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.ExpandAvailableInventoryReqVO;
|
||||
import cn.code.nl.module.wms.dal.mysql.iostorinvdtl.IostorinvDtlMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class IostorInvServiceImplTest {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void expandAvailableInventoryShouldDeduplicateBoxesAndKeepWarehouseIsolation() throws Exception {
|
||||
List<String> queriedVehicleCodes = new ArrayList<>();
|
||||
IostorinvDtlMapper mapper = (IostorinvDtlMapper) Proxy.newProxyInstance(
|
||||
IostorinvDtlMapper.class.getClassLoader(), new Class<?>[]{IostorinvDtlMapper.class},
|
||||
(proxy, method, args) -> {
|
||||
if (!"selectAvailableInventoryByVehicleCodes".equals(method.getName())) {
|
||||
throw new UnsupportedOperationException(method.getName());
|
||||
}
|
||||
assertEquals("STOR-001", args[0]);
|
||||
queriedVehicleCodes.addAll((Collection<String>) args[1]);
|
||||
return List.of(inventory("BOX-001", "PCSN-001", "STOR-001"),
|
||||
inventory("BOX-001", "PCSN-002", "STOR-001"));
|
||||
});
|
||||
IostorInvServiceImpl service = new IostorInvServiceImpl();
|
||||
Field mapperField = IostorInvServiceImpl.class.getDeclaredField("iostorinvDtlMapper");
|
||||
mapperField.setAccessible(true);
|
||||
mapperField.set(service, mapper);
|
||||
|
||||
ExpandAvailableInventoryReqVO reqVO = new ExpandAvailableInventoryReqVO();
|
||||
reqVO.setStorId("STOR-001");
|
||||
reqVO.setVehicleCodes(List.of("BOX-001", "BOX-001"));
|
||||
|
||||
List<AvailableInventoryRespVO> result = service.expandAvailableInventory(reqVO);
|
||||
|
||||
assertEquals(List.of("BOX-001"), queriedVehicleCodes);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.stream().allMatch(item -> "BOX-001".equals(item.getVehicleCode())));
|
||||
assertTrue(result.stream().allMatch(item -> "STOR-001".equals(item.getStorId())));
|
||||
assertEquals(2, result.stream().map(AvailableInventoryRespVO::getPcsn).distinct().count());
|
||||
}
|
||||
|
||||
@Test
|
||||
void availableInventorySqlShouldFilterWarehouseStatusDeletedAndAvailableQuantity() throws Exception {
|
||||
String mapperResource = "mapper/iostorinvdtl/IostorinvDtlMapper.xml";
|
||||
try (InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(mapperResource)) {
|
||||
assertNotNull(input, "Mapper XML 应存在于测试类路径");
|
||||
String sql = new String(input.readAllBytes(), StandardCharsets.UTF_8);
|
||||
assertTrue(sql.contains("sa.stor_id = #{storId}"));
|
||||
assertTrue(sql.contains("gp.status = '可用'"));
|
||||
assertTrue(sql.contains("gp.qty - gp.frozen_qty > 0"));
|
||||
assertTrue(sql.contains("gp.deleted = 0"));
|
||||
assertTrue(sql.contains("sa.deleted = 0"));
|
||||
assertTrue(sql.contains("mb.deleted = 0"));
|
||||
}
|
||||
}
|
||||
|
||||
private static AvailableInventoryRespVO inventory(String vehicleCode, String pcsn, String storId) {
|
||||
AvailableInventoryRespVO inventory = new AvailableInventoryRespVO();
|
||||
inventory.setVehicleCode(vehicleCode);
|
||||
inventory.setPcsn(pcsn);
|
||||
inventory.setStorId(storId);
|
||||
return inventory;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
DROP TABLE IF EXISTS wms_group_plate;
|
||||
DROP TABLE IF EXISTS wms_structattr;
|
||||
DROP TABLE IF EXISTS base_materialbase;
|
||||
|
||||
CREATE TABLE base_materialbase (
|
||||
material_id BIGINT PRIMARY KEY,
|
||||
material_name VARCHAR(64),
|
||||
deleted BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE wms_structattr (
|
||||
struct_id VARCHAR(64) PRIMARY KEY,
|
||||
storagevehicle_code VARCHAR(64),
|
||||
stor_id VARCHAR(64),
|
||||
stor_code VARCHAR(64),
|
||||
stor_name VARCHAR(64),
|
||||
deleted BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE wms_group_plate (
|
||||
group_id BIGINT PRIMARY KEY,
|
||||
vehicle_code VARCHAR(64),
|
||||
status VARCHAR(16),
|
||||
material_id VARCHAR(64),
|
||||
material_code VARCHAR(64),
|
||||
pcsn VARCHAR(64),
|
||||
qty DECIMAL(18, 6),
|
||||
frozen_qty DECIMAL(18, 6),
|
||||
qty_unit_id VARCHAR(64),
|
||||
qty_unit_name VARCHAR(64),
|
||||
ext_code VARCHAR(64),
|
||||
ext_type VARCHAR(64),
|
||||
ext_dtl_code VARCHAR(64),
|
||||
deleted BOOLEAN NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO base_materialbase(material_id, material_name, deleted)
|
||||
VALUES (1001, '材料一', FALSE), (1002, '已删除材料', TRUE);
|
||||
|
||||
INSERT INTO wms_structattr(struct_id, storagevehicle_code, stor_id, stor_code, stor_name, deleted)
|
||||
VALUES ('S-001', 'BOX-001', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE),
|
||||
('S-002', 'BOX-001', 'STOR-002', 'STOR-CODE-002', '二号仓', FALSE),
|
||||
('S-003', 'BOX-002', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE),
|
||||
('S-004', 'BOX-003', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE),
|
||||
('S-005', 'BOX-004', 'STOR-001', 'STOR-CODE-001', '一号仓', FALSE),
|
||||
('S-006', 'BOX-005', 'STOR-001', 'STOR-CODE-001', '一号仓', TRUE);
|
||||
|
||||
INSERT INTO wms_group_plate(group_id, vehicle_code, status, material_id, material_code, pcsn,
|
||||
qty, frozen_qty, qty_unit_id, qty_unit_name, ext_code, ext_type,
|
||||
ext_dtl_code, deleted)
|
||||
VALUES (1, 'BOX-001', '可用', '1001', 'MAT-001', 'PCSN-001', 10, 2, 'UNIT-1', '卷', 'EXT-1', 'TYPE-1', 'DTL-1', FALSE),
|
||||
(2, 'BOX-001', '可用', '1001', 'MAT-001', 'PCSN-002', 5, 1, 'UNIT-1', '卷', 'EXT-2', 'TYPE-1', 'DTL-2', FALSE),
|
||||
(3, 'BOX-002', '不可用', '1001', 'MAT-001', 'PCSN-003', 10, 0, 'UNIT-1', '卷', 'EXT-3', 'TYPE-1', 'DTL-3', FALSE),
|
||||
(4, 'BOX-003', '可用', '1001', 'MAT-001', 'PCSN-004', 10, 10, 'UNIT-1', '卷', 'EXT-4', 'TYPE-1', 'DTL-4', FALSE),
|
||||
(5, 'BOX-004', '可用', '1001', 'MAT-001', 'PCSN-005', 10, 0, 'UNIT-1', '卷', 'EXT-5', 'TYPE-1', 'DTL-5', TRUE),
|
||||
(6, 'BOX-005', '可用', '1001', 'MAT-001', 'PCSN-006', 10, 0, 'UNIT-1', '卷', 'EXT-6', 'TYPE-1', 'DTL-6', FALSE);
|
||||
Reference in New Issue
Block a user