14 changed files with 576 additions and 48 deletions
@ -0,0 +1,60 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<groupId>cn.iocoder.boot</groupId> |
|||
<artifactId>yudao-framework</artifactId> |
|||
<version>${revision}</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<artifactId>yudao-spring-boot-starter-test</artifactId> |
|||
<packaging>jar</packaging> |
|||
|
|||
<name>${project.artifactId}</name> |
|||
<description>测试组件,用于单元测试、集成测试</description> |
|||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>cn.iocoder.boot</groupId> |
|||
<artifactId>yudao-common</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- DB 相关 --> |
|||
<dependency> |
|||
<groupId>cn.iocoder.boot</groupId> |
|||
<artifactId>yudao-spring-boot-starter-mybatis</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>cn.iocoder.boot</groupId> |
|||
<artifactId>yudao-spring-boot-starter-redis</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- Test 测试相关 --> |
|||
<dependency> |
|||
<groupId>org.mockito</groupId> |
|||
<artifactId>mockito-inline</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-test</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.h2database</groupId> <!-- 单元测试,我们采用 H2 作为数据库 --> |
|||
<artifactId>h2</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.github.fppt</groupId> <!-- 单元测试,我们采用内嵌的 Redis 数据库 --> |
|||
<artifactId>jedis-mock</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>uk.co.jemos.podam</groupId> <!-- 单元测试,随机生成 POJO 类 --> |
|||
<artifactId>podam</artifactId> |
|||
</dependency> |
|||
</dependencies> |
|||
</project> |
|||
@ -0,0 +1,35 @@ |
|||
package cn.iocoder.yudao.framework.test.config; |
|||
|
|||
import com.github.fppt.jedismock.RedisServer; |
|||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.context.annotation.Lazy; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* Redis 测试 Configuration,主要实现内嵌 Redis 的启动 |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@Configuration(proxyBeanMethods = false) |
|||
@Lazy(false) // 禁止延迟加载
|
|||
@EnableConfigurationProperties(RedisProperties.class) |
|||
public class RedisTestConfiguration { |
|||
|
|||
/** |
|||
* 创建模拟的 Redis Server 服务器 |
|||
*/ |
|||
@Bean |
|||
public RedisServer redisServer(RedisProperties properties) throws IOException { |
|||
RedisServer redisServer = new RedisServer(properties.getPort()); |
|||
// 一次执行多个单元测试时,貌似创建多个 spring 容器,导致不进行 stop。这样,就导致端口被占用,无法启动。。。
|
|||
try { |
|||
redisServer.start(); |
|||
} catch (Exception ignore) {} |
|||
return redisServer; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,52 @@ |
|||
package cn.iocoder.yudao.framework.test.config; |
|||
|
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; |
|||
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; |
|||
import org.springframework.boot.sql.init.AbstractScriptDatabaseInitializer; |
|||
import org.springframework.boot.sql.init.DatabaseInitializationSettings; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.context.annotation.Lazy; |
|||
|
|||
import javax.sql.DataSource; |
|||
|
|||
/** |
|||
* SQL 初始化的测试 Configuration |
|||
* |
|||
* 为什么不使用 org.springframework.boot.autoconfigure.sql.init.DataSourceInitializationConfiguration 呢? |
|||
* 因为我们在单元测试会使用 spring.main.lazy-initialization 为 true,开启延迟加载。此时,会导致 DataSourceInitializationConfiguration 初始化 |
|||
* 不过呢,当前类的实现代码,基本是复制 DataSourceInitializationConfiguration 的哈! |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@Configuration(proxyBeanMethods = false) |
|||
@ConditionalOnMissingBean(AbstractScriptDatabaseInitializer.class) |
|||
@ConditionalOnSingleCandidate(DataSource.class) |
|||
@ConditionalOnClass(name = "org.springframework.jdbc.datasource.init.DatabasePopulator") |
|||
@Lazy(value = false) // 禁止延迟加载
|
|||
@EnableConfigurationProperties(SqlInitializationProperties.class) |
|||
public class SqlInitializationTestConfiguration { |
|||
|
|||
@Bean |
|||
public DataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, |
|||
SqlInitializationProperties initializationProperties) { |
|||
DatabaseInitializationSettings settings = createFrom(initializationProperties); |
|||
return new DataSourceScriptDatabaseInitializer(dataSource, settings); |
|||
} |
|||
|
|||
static DatabaseInitializationSettings createFrom(SqlInitializationProperties properties) { |
|||
DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); |
|||
settings.setSchemaLocations(properties.getSchemaLocations()); |
|||
settings.setDataLocations(properties.getDataLocations()); |
|||
settings.setContinueOnError(properties.isContinueOnError()); |
|||
settings.setSeparator(properties.getSeparator()); |
|||
settings.setEncoding(properties.getEncoding()); |
|||
settings.setMode(properties.getMode()); |
|||
return settings; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
package cn.iocoder.yudao.framework.test.core.ut; |
|||
|
|||
import cn.hutool.extra.spring.SpringUtil; |
|||
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.test.config.RedisTestConfiguration; |
|||
import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration; |
|||
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure; |
|||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; |
|||
import org.redisson.spring.starter.RedissonAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.context.annotation.Import; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
import org.springframework.test.context.jdbc.Sql; |
|||
|
|||
/** |
|||
* 依赖内存 DB + Redis 的单元测试 |
|||
* |
|||
* 相比 {@link BaseDbUnitTest} 来说,额外增加了内存 Redis |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisUnitTest.Application.class) |
|||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
|||
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
|
|||
public class BaseDbAndRedisUnitTest { |
|||
|
|||
@Import({ |
|||
// DB 配置类
|
|||
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
|
|||
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
|
|||
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
|
|||
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
|
|||
SqlInitializationTestConfiguration.class, // SQL 初始化
|
|||
// MyBatis 配置类
|
|||
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
|
|||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
|||
|
|||
// Redis 配置类
|
|||
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
|
|||
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
|
|||
RedisAutoConfiguration.class, // Spring Redis 自动配置类
|
|||
RedissonAutoConfiguration.class, // Redisson 自动配置类
|
|||
|
|||
// 其它配置类
|
|||
SpringUtil.class |
|||
}) |
|||
public static class Application { |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
package cn.iocoder.yudao.framework.test.core.ut; |
|||
|
|||
import cn.hutool.extra.spring.SpringUtil; |
|||
import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.test.config.SqlInitializationTestConfiguration; |
|||
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure; |
|||
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; |
|||
import com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.context.annotation.Import; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
import org.springframework.test.context.jdbc.Sql; |
|||
|
|||
/** |
|||
* 依赖内存 DB 的单元测试 |
|||
* |
|||
* 注意,Service 层同样适用。对于 Service 层的单元测试,我们针对自己模块的 Mapper 走的是 H2 内存数据库,针对别的模块的 Service 走的是 Mock 方法 |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class) |
|||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
|||
@Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) // 每个单元测试结束后,清理 DB
|
|||
public class BaseDbUnitTest { |
|||
|
|||
@Import({ |
|||
// DB 配置类
|
|||
YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
|
|||
DataSourceAutoConfiguration.class, // Spring DB 自动配置类
|
|||
DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
|
|||
DruidDataSourceAutoConfigure.class, // Druid 自动配置类
|
|||
SqlInitializationTestConfiguration.class, // SQL 初始化
|
|||
// MyBatis 配置类
|
|||
YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
|
|||
MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
|
|||
MybatisPlusJoinAutoConfiguration.class, // MyBatis 的Join配置类
|
|||
|
|||
// 其它配置类
|
|||
SpringUtil.class |
|||
}) |
|||
public static class Application { |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
package cn.iocoder.yudao.framework.test.core.ut; |
|||
|
|||
import org.junit.jupiter.api.extension.ExtendWith; |
|||
import org.mockito.junit.jupiter.MockitoExtension; |
|||
|
|||
/** |
|||
* 纯 Mockito 的单元测试 |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@ExtendWith(MockitoExtension.class) |
|||
public class BaseMockitoUnitTest { |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
package cn.iocoder.yudao.framework.test.core.ut; |
|||
|
|||
import cn.hutool.extra.spring.SpringUtil; |
|||
import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; |
|||
import cn.iocoder.yudao.framework.test.config.RedisTestConfiguration; |
|||
import org.redisson.spring.starter.RedissonAutoConfiguration; |
|||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; |
|||
import org.springframework.boot.test.context.SpringBootTest; |
|||
import org.springframework.context.annotation.Import; |
|||
import org.springframework.test.context.ActiveProfiles; |
|||
|
|||
/** |
|||
* 依赖内存 Redis 的单元测试 |
|||
* |
|||
* 相比 {@link BaseDbUnitTest} 来说,从内存 DB 改成了内存 Redis |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisUnitTest.Application.class) |
|||
@ActiveProfiles("unit-test") // 设置使用 application-unit-test 配置文件
|
|||
public class BaseRedisUnitTest { |
|||
|
|||
@Import({ |
|||
// Redis 配置类
|
|||
RedisTestConfiguration.class, // Redis 测试配置类,用于启动 RedisServer
|
|||
RedisAutoConfiguration.class, // Spring Redis 自动配置类
|
|||
YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
|
|||
RedissonAutoConfiguration.class, // Redisson 自动配置类
|
|||
|
|||
// 其它配置类
|
|||
SpringUtil.class |
|||
}) |
|||
public static class Application { |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
/** |
|||
* 提供单元测试 Unit Test 的基类 |
|||
*/ |
|||
package cn.iocoder.yudao.framework.test.core.ut; |
|||
@ -0,0 +1,101 @@ |
|||
package cn.iocoder.yudao.framework.test.core.util; |
|||
|
|||
import cn.hutool.core.util.ArrayUtil; |
|||
import cn.hutool.core.util.ReflectUtil; |
|||
import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
|||
import cn.iocoder.yudao.framework.common.exception.ServiceException; |
|||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; |
|||
import org.junit.jupiter.api.Assertions; |
|||
import org.junit.jupiter.api.function.Executable; |
|||
|
|||
import java.lang.reflect.Field; |
|||
import java.util.Arrays; |
|||
import java.util.Objects; |
|||
|
|||
import static org.junit.jupiter.api.Assertions.assertThrows; |
|||
|
|||
/** |
|||
* 单元测试,assert 断言工具类 |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
public class AssertUtils { |
|||
|
|||
/** |
|||
* 比对两个对象的属性是否一致 |
|||
* |
|||
* 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 |
|||
* |
|||
* @param expected 期望对象 |
|||
* @param actual 实际对象 |
|||
* @param ignoreFields 忽略的属性数组 |
|||
*/ |
|||
public static void assertPojoEquals(Object expected, Object actual, String... ignoreFields) { |
|||
Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); |
|||
Arrays.stream(expectedFields).forEach(expectedField -> { |
|||
// 忽略 jacoco 自动生成的 $jacocoData 属性的情况
|
|||
if (expectedField.isSynthetic()) { |
|||
return; |
|||
} |
|||
// 如果是忽略的属性,则不进行比对
|
|||
if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { |
|||
return; |
|||
} |
|||
// 忽略不存在的属性
|
|||
Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); |
|||
if (actualField == null) { |
|||
return; |
|||
} |
|||
// 比对
|
|||
Assertions.assertEquals( |
|||
ReflectUtil.getFieldValue(expected, expectedField), |
|||
ReflectUtil.getFieldValue(actual, actualField), |
|||
String.format("Field(%s) 不匹配", expectedField.getName()) |
|||
); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 比对两个对象的属性是否一致 |
|||
* |
|||
* 注意,如果 expected 存在的属性,actual 不存在的时候,会进行忽略 |
|||
* |
|||
* @param expected 期望对象 |
|||
* @param actual 实际对象 |
|||
* @param ignoreFields 忽略的属性数组 |
|||
* @return 是否一致 |
|||
*/ |
|||
public static boolean isPojoEquals(Object expected, Object actual, String... ignoreFields) { |
|||
Field[] expectedFields = ReflectUtil.getFields(expected.getClass()); |
|||
return Arrays.stream(expectedFields).allMatch(expectedField -> { |
|||
// 如果是忽略的属性,则不进行比对
|
|||
if (ArrayUtil.contains(ignoreFields, expectedField.getName())) { |
|||
return true; |
|||
} |
|||
// 忽略不存在的属性
|
|||
Field actualField = ReflectUtil.getField(actual.getClass(), expectedField.getName()); |
|||
if (actualField == null) { |
|||
return true; |
|||
} |
|||
return Objects.equals(ReflectUtil.getFieldValue(expected, expectedField), |
|||
ReflectUtil.getFieldValue(actual, actualField)); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* 执行方法,校验抛出的 Service 是否符合条件 |
|||
* |
|||
* @param executable 业务异常 |
|||
* @param errorCode 错误码对象 |
|||
* @param messageParams 消息参数 |
|||
*/ |
|||
public static void assertServiceException(Executable executable, ErrorCode errorCode, Object... messageParams) { |
|||
// 调用方法
|
|||
ServiceException serviceException = assertThrows(ServiceException.class, executable); |
|||
// 校验错误码
|
|||
Assertions.assertEquals(errorCode.getCode(), serviceException.getCode(), "错误码不匹配"); |
|||
String message = ServiceExceptionUtil.doFormat(errorCode.getCode(), errorCode.getMsg(), messageParams); |
|||
Assertions.assertEquals(message, serviceException.getMessage(), "错误提示不匹配"); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,146 @@ |
|||
package cn.iocoder.yudao.framework.test.core.util; |
|||
|
|||
import cn.hutool.core.date.LocalDateTimeUtil; |
|||
import cn.hutool.core.util.ArrayUtil; |
|||
import cn.hutool.core.util.RandomUtil; |
|||
import cn.hutool.core.util.StrUtil; |
|||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
|||
import uk.co.jemos.podam.api.PodamFactory; |
|||
import uk.co.jemos.podam.api.PodamFactoryImpl; |
|||
|
|||
import java.lang.reflect.Type; |
|||
import java.time.LocalDateTime; |
|||
import java.util.Arrays; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.function.Consumer; |
|||
import java.util.stream.Collectors; |
|||
import java.util.stream.Stream; |
|||
|
|||
/** |
|||
* 随机工具类 |
|||
* |
|||
* @author 芋道源码 |
|||
*/ |
|||
public class RandomUtils { |
|||
|
|||
private static final int RANDOM_STRING_LENGTH = 10; |
|||
|
|||
private static final int TINYINT_MAX = 127; |
|||
|
|||
private static final int RANDOM_DATE_MAX = 30; |
|||
|
|||
private static final int RANDOM_COLLECTION_LENGTH = 5; |
|||
|
|||
private static final PodamFactory PODAM_FACTORY = new PodamFactoryImpl(); |
|||
|
|||
static { |
|||
// 字符串
|
|||
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(String.class, |
|||
(dataProviderStrategy, attributeMetadata, map) -> randomString()); |
|||
// Integer
|
|||
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Integer.class, (dataProviderStrategy, attributeMetadata, map) -> { |
|||
// 如果是 status 的字段,返回 0 或 1
|
|||
if ("status".equals(attributeMetadata.getAttributeName())) { |
|||
return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); |
|||
} |
|||
// 如果是 type、status 结尾的字段,返回 tinyint 范围
|
|||
if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(), |
|||
"type", "status", "category", "scope", "result")) { |
|||
return RandomUtil.randomInt(0, TINYINT_MAX + 1); |
|||
} |
|||
return RandomUtil.randomInt(); |
|||
}); |
|||
// LocalDateTime
|
|||
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(LocalDateTime.class, |
|||
(dataProviderStrategy, attributeMetadata, map) -> randomLocalDateTime()); |
|||
// Boolean
|
|||
PODAM_FACTORY.getStrategy().addOrReplaceTypeManufacturer(Boolean.class, (dataProviderStrategy, attributeMetadata, map) -> { |
|||
// 如果是 deleted 的字段,返回非删除
|
|||
if ("deleted".equals(attributeMetadata.getAttributeName())) { |
|||
return false; |
|||
} |
|||
return RandomUtil.randomBoolean(); |
|||
}); |
|||
} |
|||
|
|||
public static String randomString() { |
|||
return RandomUtil.randomString(RANDOM_STRING_LENGTH); |
|||
} |
|||
|
|||
public static Long randomLongId() { |
|||
return RandomUtil.randomLong(0, Long.MAX_VALUE); |
|||
} |
|||
|
|||
public static Integer randomInteger() { |
|||
return RandomUtil.randomInt(0, Integer.MAX_VALUE); |
|||
} |
|||
|
|||
public static Date randomDate() { |
|||
return RandomUtil.randomDay(0, RANDOM_DATE_MAX); |
|||
} |
|||
|
|||
public static LocalDateTime randomLocalDateTime() { |
|||
// 设置 Nano 为零的原因,避免 MySQL、H2 存储不到时间戳
|
|||
return LocalDateTimeUtil.of(randomDate()).withNano(0); |
|||
} |
|||
|
|||
public static Short randomShort() { |
|||
return (short) RandomUtil.randomInt(0, Short.MAX_VALUE); |
|||
} |
|||
|
|||
public static <T> Set<T> randomSet(Class<T> clazz) { |
|||
return Stream.iterate(0, i -> i).limit(RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH)) |
|||
.map(i -> randomPojo(clazz)).collect(Collectors.toSet()); |
|||
} |
|||
|
|||
public static Integer randomCommonStatus() { |
|||
return RandomUtil.randomEle(CommonStatusEnum.values()).getStatus(); |
|||
} |
|||
|
|||
public static String randomEmail() { |
|||
return randomString() + "@qq.com"; |
|||
} |
|||
|
|||
public static String randomMobile() { |
|||
return "13800138" + RandomUtil.randomNumbers(3); |
|||
} |
|||
|
|||
public static String randomURL() { |
|||
return "https://www.iocoder.cn/" + randomString(); |
|||
} |
|||
|
|||
@SafeVarargs |
|||
public static <T> T randomPojo(Class<T> clazz, Consumer<T>... consumers) { |
|||
T pojo = PODAM_FACTORY.manufacturePojo(clazz); |
|||
// 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理
|
|||
if (ArrayUtil.isNotEmpty(consumers)) { |
|||
Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); |
|||
} |
|||
return pojo; |
|||
} |
|||
|
|||
@SafeVarargs |
|||
public static <T> T randomPojo(Class<T> clazz, Type type, Consumer<T>... consumers) { |
|||
T pojo = PODAM_FACTORY.manufacturePojo(clazz, type); |
|||
// 非空时,回调逻辑。通过它,可以实现 Pojo 的进一步处理
|
|||
if (ArrayUtil.isNotEmpty(consumers)) { |
|||
Arrays.stream(consumers).forEach(consumer -> consumer.accept(pojo)); |
|||
} |
|||
return pojo; |
|||
} |
|||
|
|||
@SafeVarargs |
|||
public static <T> List<T> randomPojoList(Class<T> clazz, Consumer<T>... consumers) { |
|||
int size = RandomUtil.randomInt(1, RANDOM_COLLECTION_LENGTH); |
|||
return randomPojoList(clazz, size, consumers); |
|||
} |
|||
|
|||
@SafeVarargs |
|||
public static <T> List<T> randomPojoList(Class<T> clazz, int size, Consumer<T>... consumers) { |
|||
return Stream.iterate(0, i -> i).limit(size).map(o -> randomPojo(clazz, consumers)) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
/** |
|||
* 测试组件,用于单元测试、集成测试等等 |
|||
*/ |
|||
package cn.iocoder.yudao.framework.test; |
|||
@ -0,0 +1 @@ |
|||
<https://www.iocoder.cn/Spring-Boot/Unit-Test/?yudao> |
|||
Loading…
Reference in new issue