diff --git a/ruoyi-modules/ruoyi-demo/pom.xml b/ruoyi-modules/ruoyi-demo/pom.xml
index 119fe61b7823be96cf19f4e5d3d7fffbba830fbc..532153adf2f15634dceae0e76837844792b4c21c 100644
--- a/ruoyi-modules/ruoyi-demo/pom.xml
+++ b/ruoyi-modules/ruoyi-demo/pom.xml
@@ -102,7 +102,16 @@
org.dromara
ruoyi-common-websocket
-
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.mysql
+ mysql-connector-j
+ test
+
diff --git a/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/BaseDbUnitTest.java b/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/BaseDbUnitTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..83ebd29618f206f178483a57f2e1d4d4d57bb91b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/BaseDbUnitTest.java
@@ -0,0 +1,47 @@
+package org.dromara.demo;
+
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAssistConfiguration;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceCreatorAutoConfiguration;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusLanguageDriverAutoConfiguration;
+import io.github.linpeilie.Converter;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.mybatis.config.MybatisPlusConfig;
+import org.dromara.common.redis.config.properties.RedissonProperties;
+import org.dromara.common.tenant.config.TenantConfig;
+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;
+
+/**
+ * 可测试Service层的单元测试
+ *
+ *
+ * @author zhouchang
+ */
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbUnitTest.Application.class)
+@ActiveProfiles("test")
+public class BaseDbUnitTest {
+ //导入顺序有严格顺序,不能随意调整。
+ @Import({
+ Converter.class,
+ SpringUtils.class,
+ DynamicDataSourceProperties.class,
+ DynamicDataSourceAssistConfiguration.class,
+ DynamicDataSourceCreatorAutoConfiguration.class,
+ DynamicRoutingDataSource.class,
+ DataSourceTransactionManagerAutoConfiguration.class,
+ RedissonProperties.class,
+ MybatisPlusLanguageDriverAutoConfiguration.class,
+ MybatisPlusConfig.class,
+ TenantConfig.class,
+ MybatisPlusAutoConfiguration.class,
+ })
+ public static class Application {
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/service/impl/TestDemoServiceImplTest.java b/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/service/impl/TestDemoServiceImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d645bd8f3293fa5a56781c5af17ae16d3580867d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-demo/src/test/java/org/dromara/demo/service/impl/TestDemoServiceImplTest.java
@@ -0,0 +1,53 @@
+package org.dromara.demo.service.impl;
+
+import jakarta.annotation.Resource;
+import org.dromara.demo.BaseDbUnitTest;
+import org.dromara.demo.domain.bo.TestDemoBo;
+import org.dromara.demo.domain.vo.TestDemoVo;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.transaction.annotation.Transactional;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * 测试 TestDemoServiceImpl 的测试类
+ */
+@Import(
+ value = {
+ TestDemoServiceImpl.class
+ }
+)
+@DisplayName("测试单表单元测试案例")
+class TestDemoServiceImplTest extends BaseDbUnitTest {
+
+ private @Resource TestDemoServiceImpl testDemoService;
+
+ @Test
+ @Order(1)
+ @DisplayName("测试查询单个数据")
+ void testQueryById() {
+ TestDemoVo testDemoVo = testDemoService.queryById(1L);
+ assertNotNull(testDemoVo, "查询结果不应为 null");
+ }
+
+ @Test
+ @Order(1)
+ @DisplayName("测试插入单个数据")
+ @Transactional
+ @Rollback
+ void testInsertByBo() {
+ TestDemoBo testDemoBo = new TestDemoBo();
+ testDemoBo.setDeptId(101L);
+ testDemoBo.setUserId(1L);
+ testDemoBo.setOrderNum(1);
+ testDemoBo.setTestKey("test_key" + System.currentTimeMillis());
+ testDemoBo.setValue("test_value" + System.currentTimeMillis());
+ testDemoBo.setVersion(1L);
+ Boolean b = testDemoService.insertByBo(testDemoBo);
+ assertTrue(b, "插入失败");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-demo/src/test/resources/application-test.yml b/ruoyi-modules/ruoyi-demo/src/test/resources/application-test.yml
new file mode 100644
index 0000000000000000000000000000000000000000..33bf2bbe22136c54918625662d34c9674f1b0793
--- /dev/null
+++ b/ruoyi-modules/ruoyi-demo/src/test/resources/application-test.yml
@@ -0,0 +1,108 @@
+# MyBatisPlus配置
+# https://baomidou.com/config/
+mybatis-plus:
+ # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
+ enableLogicDelete: true
+ # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper
+ mapperPackage: org.dromara.**.mapper
+ # 对应的 XML 文件位置
+ mapperLocations: classpath*:mapper/**/*Mapper.xml
+ # 实体扫描,多个package用逗号或者分号分隔
+ typeAliasesPackage: org.dromara.**.domain
+ global-config:
+ dbConfig:
+ # 主键类型
+ # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+ # 如需改为自增 需要将数据库表全部设置为自增
+ idType: ASSIGN_ID
+
+tenant:
+ # 是否开启
+ enable: true
+ # 排除表
+ excludes:
+ - sys_menu
+ - sys_tenant
+ - sys_tenant_package
+ - sys_role_dept
+ - sys_role_menu
+ - sys_user_post
+ - sys_user_role
+ - sys_client
+ - sys_oss_config
+spring:
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+ dynamic:
+ # 性能分析插件(有性能损耗 不建议生产环境使用)
+ p6spy: true
+ # 设置默认的数据源或者数据源组,默认值即为 master
+ primary: master
+ # 严格模式 匹配不到数据源则报错
+ strict: true
+ datasource:
+ # 主库数据源
+ master:
+ type: ${spring.datasource.type}
+ driverClassName: com.mysql.cj.jdbc.Driver
+ # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
+ # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
+ url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+ username: root
+ password: root
+
+ hikari:
+ # 最大连接池数量
+ maxPoolSize: 20
+ # 最小空闲线程数量
+ minIdle: 10
+ # 配置获取连接等待超时的时间
+ connectionTimeout: 30000
+ # 校验超时时间
+ validationTimeout: 5000
+ # 空闲连接存活最大时间,默认10分钟
+ idleTimeout: 600000
+ # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟
+ maxLifetime: 1800000
+ # 多久检查一次连接的活性
+ keepaliveTime: 30000
+
+--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
+spring.data:
+ redis:
+ # 地址
+ host: localhost
+ # 端口,默认为6379
+ port: 6379
+ # 数据库索引
+ database: 0
+ # redis 密码必须配置
+ password: ruoyi123
+ # 连接超时时间
+ timeout: 10s
+ # 是否开启ssl
+ ssl.enabled: false
+
+# redisson 配置
+redisson:
+ # redis key前缀
+ keyPrefix:
+ # 线程池数量
+ threads: 4
+ # Netty线程池数量
+ nettyThreads: 8
+ # 单节点配置
+ singleServerConfig:
+ # 客户端名称 不能用中文
+ clientName: RuoYi-Vue-Plus
+ # 最小空闲连接数
+ connectionMinimumIdleSize: 8
+ # 连接池大小
+ connectionPoolSize: 32
+ # 连接空闲超时,单位:毫秒
+ idleConnectionTimeout: 10000
+ # 命令等待超时,单位:毫秒
+ timeout: 3000
+ # 发布和订阅连接池大小
+ subscriptionConnectionPoolSize: 50