前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、项目配置

1、pom

<!--数据源-->
  <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
      <version>3.6.1</version>
  </dependency>
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>${com-alibaba-druid.version}</version>
  </dependency>
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.45</version>
  </dependency>

  <!--mybatis-plus-->
  <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-boot-starter</artifactId>
      <version>${mybatis-plus-boot-starter.version}</version>
  </dependency>

  <!--h2database -->
  <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>2.1.214</version>
      <scope>test</scope>
  </dependency>
<!-- mockito  -->
  <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-inline</artifactId>
      <version>5.2.0</version>
      <scope>test</scope>
  </dependency>

  <!--junit5-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>2.3.4.RELEASE</version>
  </dependency>

2、YML

####################################
### DB
####################################
spring:
  redis:
    host: 127.0.0.1
    port: 6379
  datasource:
    dynamic:
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: healerjean
      # 设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源
      strict: true
      druid:
        # 初始化时建立物理连接的个数
        initialSize: 5
        # 最小连接池数量
        minIdle: 5
        # 最大连接池数量
        maxActive: 20
        # 获取连接等待超时时间
        maxWait: 60000
        ## 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
        timeBetweenEvictionRunsMillis: 60000
        ## 连接保持空闲而不被驱逐的最小时间
        minEvictableIdleTimeMillis: 300000
        # 用来检测连接是否有效的sql,要求是一个查询语句
        validationQuery: SELECT 1 FROM DUAL
        # 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
        testWhileIdle: true
        # 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
        testOnBorrow: false
        # 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
        testOnReturn: false
        #打開PSCache,並指定每個連接上PSCache的大小。oracle設爲true,mysql設爲false。分庫分表較多推薦設置爲false
        pool-prepared-statements: false
        max-pool-prepared-statement-per-connection-size: 20
        stat:
          #日志输出执行慢的SQL
          log-slow-sql: true
          #slowSqlMillis的缺省值为3000,也就是3秒。
          slow-sql-millis: 2000
      datasource:
        healerjean:
          # 3.2.0开始支持SPI可省略此配置
          driver-class-name: org.h2.Driver
          url: jdbc:h2:mem:healerjean
          init:
            schema: classpath:ut/mock/sql/init/healerjean_create.sql
            data: classpath:ut/mock/sql/init/healerjean_insert.sql
            continueOnError: false
        test:
          # 3.2.0开始支持SPI可省略此配置
          driver-class-name: org.h2.Driver
          url: jdbc:h2:mem:test
          init:
            schema: classpath:ut/mock/sql/init/test_create.sql
            data: classpath:ut/mock/sql/init/test_insert.sql
            continueOnError: false

二、数据准备

1、库 healerjean

1)healerjean_create.sql

-- 踩坑
-- 1、h2 不允许 bigint(20) int(11) 不允许为这些设置基本参数
-- 2、不允许指定 engine = innodb mysql引擎
-- 3、不支持 bigint unsigned
create table if not exists `user_demo`
(
    `id`          bigint      not null auto_increment comment '主键',
    `name`        varchar(32) not null default '' comment '姓名',
    `age`         int         not null default 0 comment '年龄',
    `phone`       varchar(32) not null default '' comment '电话',
    `email`       varchar(64) not null default '' comment '邮箱',
    `start_time`  datetime             default null comment '开始时间',
    `end_time`    datetime             default null comment '结束时间',
    `valid_flag`  int         not null default 1 comment '1有效 0 废弃',
    `create_time` datetime    not null default current_timestamp comment '创建时间',
    `update_time` datetime    not null default current_timestamp on update current_timestamp comment '更新时间',
    primary key (`id`)
);



2)healerjean_insert.sql

INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555777', '133255@gmail', null, null, 1, '2023-06-14 16:09:19', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555778', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555779', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555780', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555781', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555782', '133255@gmail', null, null, 1, '2023-06-14 16:16:18', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555783', '133255@gmail', '2020-06-11 00:00:00', '2023-06-11 00:00:00', 1, '2023-06-14 16:28:39', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('healerjean', 0, '1332555784', '133255@gmail', '2020-06-11 00:00:00', '2023-06-11 00:00:00', 1, '2023-06-14 16:29:13', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('string', 0, '1332555785', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:23', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'string', 0, '1332555786', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:34', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'string', 0, '1332555787', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:52', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'string', 0, '1332555788', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:16:14', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'string', 0, 'string', 'string', '2023-06-14 22:36:11', '2023-06-14 22:36:11', 1, '2023-06-14 22:36:31', '2023-06-14 22:36:31');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'string', 0, 'string', 'string', '2023-06-14 22:36:11', '2023-06-14 22:36:11', 1, '2023-06-14 22:38:42', '2023-06-14 22:38:42');

2、库 test

1)test_create.sql

-- 踩坑
-- 1h2 不允许 bigint(20) int(11) 不允许为这些设置基本参数
-- 2不允许指定 engine = innodb mysql引擎
-- 3不支持 bigint unsigned
create table if not exists `user_demo`
(
    `id`          bigint      not null auto_increment comment '主键',
    `name`        varchar(32) not null default '' comment '姓名',
    `age`         int         not null default 0 comment '年龄',
    `phone`       varchar(32) not null default '' comment '电话',
    `email`       varchar(64) not null default '' comment '邮箱',
    `start_time`  datetime             default null comment '开始时间',
    `end_time`    datetime             default null comment '结束时间',
    `valid_flag`  int         not null default 1 comment '1有效 0 废弃',
    `create_time` datetime    not null default current_timestamp comment '创建时间',
    `update_time` datetime    not null default current_timestamp on update current_timestamp comment '更新时间',
    primary key (`id`)
);



2)test_insert.sql

INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test1', 0, '1332555777', '133255@gmail', null, null, 1, '2023-06-14 16:09:19', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test2', 0, '1332555778', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test3', 0, '1332555779', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test4', 0, '1332555780', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test5', 0, '1332555781', '133255@gmail', null, null, 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test6', 0, '1332555782', '133255@gmail', null, null, 1, '2023-06-14 16:16:18', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test7', 0, '1332555783', '133255@gmail', '2020-06-11 00:00:00', '2023-06-11 00:00:00', 1, '2023-06-14 16:28:39', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test', 0, '1332555784', '133255@gmail', '2020-06-11 00:00:00', '2023-06-11 00:00:00', 1, '2023-06-14 16:29:13', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ('test', 0, '1332555785', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:23', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'test', 0, '1332555786', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:34', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'test', 0, '1332555787', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:14:52', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'test', 0, '1332555788', '133255@gmail', '2023-06-14 21:14:18', '2023-06-14 21:14:18', 1, '2023-06-14 21:16:14', '2023-06-14 22:01:10');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'test', 0, 'string', 'string', '2023-06-14 22:36:11', '2023-06-14 22:36:11', 1, '2023-06-14 22:36:31', '2023-06-14 22:36:31');
INSERT INTO user_demo ( name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time) VALUES ( 'test', 0, 'string', 'string', '2023-06-14 22:36:11', '2023-06-14 22:36:11', 1, '2023-06-14 22:38:42', '2023-06-14 22:38:42');

三、单元测试

1、数据准备

1)库 healerjean

INSERT INTO user_demo (id, name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (100,'healerjean1', 30, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (101,'healerjean2', 31, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (102,'healerjean3', 32, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (103,'healerjean4', 33, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

2)库 test

INSERT INTO user_demo (id, name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (100,'test1', 1, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (101,'test2', 2, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (102,'test3', 3, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

INSERT INTO user_demo (id,name, age, phone, email, start_time, end_time, valid_flag, create_time, update_time)
VALUES (103,'test4', 4, '1332555778', 'healerjean@gmail', '2023-06-15 00:01:00', '2023-06-15 00:01:00', 1, '2023-06-14 16:16:17', '2023-06-14 22:01:10');

3)公共

truncate table user_demo;

2、多数据源支持

1)注解 HSqlGroup

package org.springframework.test.context.jdbc;

import java.lang.annotation.*;

/**
 * HSqlGroup
 * @author zhangyujin
 * @date 2023/6/15  15:14
 */

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HSqlGroup {
    /**
     * value
     *
     * @return NoTXSql[]
     */
    HSql[] value();
}

2)注解 HSql

package org.springframework.test.context.jdbc;

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;


/**
 * interface-HSql
 * @author zhangyujin
 * @date 2023/6/15  15:14
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Repeatable(HSqlGroup.class)
public @interface HSql {
    /**
     * value
     *
     * @return value
     */
    @AliasFor("scripts")
    String[] value() default {};

    /**
     * scripts
     *
     * @return scripts
     */
    @AliasFor("value")
    String[] scripts() default {};

    /**
     * statements
     *
     * @return statements
     */
    String[] statements() default {};

    /**
     * executionPhase
     *
     * @return executionPhase
     */
    ExecutionPhase executionPhase() default ExecutionPhase.BEFORE_TEST_METHOD;

    /**
     * config
     *
     * @return config
     */
    SqlConfig config() default @SqlConfig;

    /**
     * ExecutionPhase
     */
    enum ExecutionPhase {
        /**
         * ExecutionPhase
         */
        BEFORE_TEST_METHOD,
        AFTER_TEST_METHOD;

        ExecutionPhase() {
        }
    }
}

3)SQL监听器 BxDirectScriptsTestExecutionListener

package org.springframework.test.context.jdbc;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.jdbc.SqlConfig.ErrorMode;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import org.springframework.test.context.util.TestContextResourceUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;

/**
* BxDirectScriptsTestExecutionListener
*
* @author zhangyujin
* @date 2023/6/15  15:14
*/
@Sql
public class BxDirectScriptsTestExecutionListener extends AbstractTestExecutionListener {
  /**
   * logger
   */
  private static final Log logger = LogFactory.getLog(SqlScriptsTestExecutionListener.class);

  /**
   * BxDirectScriptsTestExecutionListener
   */
  public BxDirectScriptsTestExecutionListener() {
  }


  @Override
  public final int getOrder() {
      return 5001;
  }

  @Override
  public void beforeTestMethod(TestContext testContext) {
      this.executeSqlScripts(testContext, HSql.ExecutionPhase.BEFORE_TEST_METHOD);
  }

  @Override
  public void afterTestMethod(TestContext testContext) {
      this.executeSqlScripts(testContext, HSql.ExecutionPhase.AFTER_TEST_METHOD);
  }

  /**
   * executeSqlScripts
   *
   * @param testContext    TestContext
   * @param executionPhase NoTXSql.ExecutionPhase
   */
  private void executeSqlScripts(TestContext testContext, HSql.ExecutionPhase executionPhase) {
      boolean classLevel = false;
      Set<HSql> sqlAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(testContext.getTestMethod(), HSql.class, HSqlGroup.class);
      if (sqlAnnotations.isEmpty()) {
          sqlAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(testContext.getTestClass(), HSql.class, HSqlGroup.class);
          if (!sqlAnnotations.isEmpty()) {
              classLevel = true;
          }
      }
      for (HSql sql : sqlAnnotations) {
          this.executeSqlScripts(sql, executionPhase, testContext, classLevel);
      }
  }

  /**
   * executeSqlScripts
   *
   * @param sql            NoTXSql
   * @param executionPhase NoTXSql.ExecutionPhase
   * @param testContext    TestContext
   * @param classLevel     classLevel
   */
  private void executeSqlScripts(HSql sql, HSql.ExecutionPhase executionPhase, TestContext testContext, boolean classLevel) {
      if (executionPhase == sql.executionPhase()) {
          MergedSqlConfig mergedSqlConfig = new MergedSqlConfig(sql.config(), testContext.getTestClass());
          ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
          populator.setSqlScriptEncoding(mergedSqlConfig.getEncoding());
          populator.setSeparator(mergedSqlConfig.getSeparator());
          populator.setCommentPrefix(mergedSqlConfig.getCommentPrefixes()[0]);
          populator.setBlockCommentStartDelimiter(mergedSqlConfig.getBlockCommentStartDelimiter());
          populator.setBlockCommentEndDelimiter(mergedSqlConfig.getBlockCommentEndDelimiter());
          populator.setContinueOnError(mergedSqlConfig.getErrorMode() == ErrorMode.CONTINUE_ON_ERROR);
          populator.setIgnoreFailedDrops(mergedSqlConfig.getErrorMode() == ErrorMode.IGNORE_FAILED_DROPS);
          String[] scripts = this.getScripts(sql, testContext, classLevel);
          scripts = TestContextResourceUtils.convertToClasspathResourcePaths(testContext.getTestClass(), scripts);
          List<Resource> scriptResources = TestContextResourceUtils.convertToResourceList(testContext.getApplicationContext(), scripts);
          String[] var9 = sql.statements();
          for (String s : var9) {
              String stmt = s;
              if (StringUtils.hasText(stmt)) {
                  stmt = stmt.trim();
                  scriptResources.add(new ByteArrayResource(stmt.getBytes(), String.format("from inlined SQL statement: %s", stmt)));
              }
          }
          populator.setScripts(scriptResources.toArray(new Resource[0]));
          String dsName = mergedSqlConfig.getDataSource();
          DynamicDataSourceContextHolder.push(dsName);
          DynamicRoutingDataSource dynamicRoutingDataSource = testContext.getApplicationContext().getBean(DynamicRoutingDataSource.class);
          DataSource dataSource = dynamicRoutingDataSource.determineDataSource();
          assert dataSource != null;
          populator.execute(dataSource);
          DynamicDataSourceContextHolder.poll();

      }
  }

  /**
   * getScripts
   *
   * @param sql         NoTXSql
   * @param testContext TestContext
   * @param classLevel  classLevel
   * @return String[]
   */
  private String[] getScripts(HSql sql, TestContext testContext, boolean classLevel) {
      String[] scripts = sql.scripts();
      if (ObjectUtils.isEmpty(scripts) && ObjectUtils.isEmpty(sql.statements())) {
          scripts = new String[]{this.detectDefaultScript(testContext, classLevel)};
      }

      return scripts;
  }

  /**
   * detectDefaultScript
   *
   * @param testContext TestContext
   * @param classLevel  classLevel
   * @return String
   */
  private String detectDefaultScript(TestContext testContext, boolean classLevel) {
      Class<?> clazz = testContext.getTestClass();
      Method method = testContext.getTestMethod();
      String elementType = classLevel ? "class" : "method";
      String elementName = classLevel ? clazz.getName() : method.toString();
      String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName());
      if (!classLevel) {
          resourcePath = resourcePath + "." + method.getName();
      }

      resourcePath = resourcePath + ".sql";
      String prefixedResourcePath = "classpath:" + resourcePath;
      ClassPathResource classPathResource = new ClassPathResource(resourcePath);
      if (classPathResource.exists()) {
          if (logger.isInfoEnabled()) {
              logger.info(String.format("Detected default SQL script \"%s\" for test %s [%s]", prefixedResourcePath, elementType, elementName));
          }

          return prefixedResourcePath;
      } else {
          String msg = String.format("Could not detect default SQL script for test %s [%s]: %s does not exist. Either declare statements or scripts via @Sql or make the default SQL script available.", elementType, elementName, classPathResource);
          logger.error(msg);
          throw new IllegalStateException(msg);
      }
  }
}

3、单元测试

package com.healerjean.proj.controller;

import com.healerjean.proj.base.BaseJunit5SpringTest;
import com.healerjean.proj.common.contants.DataSourceConstant;
import com.healerjean.proj.common.data.bo.BaseRes;
import com.healerjean.proj.data.vo.UserDemoVO;
import com.healerjean.proj.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.test.context.jdbc.HSql;
import org.springframework.test.context.jdbc.SqlConfig;

import javax.annotation.Resource;

/**
 * UserDemoControllerTest
 *
 * @author zhangyujin
 * @date 2023/6/15  15:42.
 */
@Slf4j
public class UserDemoControllerJunit5Test extends BaseJunit5SpringTest {

    /**
     * userDemoController
     */
    @Resource
    private UserDemoController userDemoController;


    /**
     * 默认数据源
     */
    @ParameterizedTest
    @DisplayName("默认数据源")
    @ValueSource(longs = {100, 102, 103, 104, 999})
    @HSql(value = {"/ut/mock/sql/unit/controller/healerjean/UserDemoControllerTest/userDemos.sql"})
    @HSql(value = {"/ut/mock/sql/clean/user_demo_clean.sql"}, executionPhase = HSql.ExecutionPhase.AFTER_TEST_METHOD)
    public void testQueryUserDemoSingle(long id) {
        BaseRes<UserDemoVO> res = userDemoController.queryUserDemoSingle(id);
        log.info("[UserDemoControllerTest#testQueryUserDemoSingle] id:{}, res:{}", id, JsonUtils.toString(res));
        Assertions.assertNotNull(res, "res不能为空");
        Assertions.assertEquals(res.getSuccess(), Boolean.TRUE);
    }


    /**
     * 双数据源
     */
    @ParameterizedTest
    @DisplayName("双数据源")
    @ValueSource(longs = {1, 100, 102, 103, 104, 999})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.MASTER_HEALER_JEAN), value = {"/ut/mock/sql/unit/controller/healerjean/UserDemoControllerTest/userDemos.sql"})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.MASTER_HEALER_JEAN), value = {"/ut/mock/sql/clean/user_demo_clean.sql"}, executionPhase = HSql.ExecutionPhase.AFTER_TEST_METHOD)
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.SLAVE_TEST), value = {"/ut/mock/sql/unit/controller/test/UserDemoControllerTest/testQueryUserDemoSingle.sql"})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.SLAVE_TEST), value = {"/ut/mock/sql/clean/user_demo_clean.sql"}, executionPhase = HSql.ExecutionPhase.AFTER_TEST_METHOD)
    public void testQueryUserDemoSingleDbTest(long id) {
        BaseRes<UserDemoVO> res = userDemoController.queryUserDemoSingle(id);
        log.info("[UserDemoControllerTest#testQueryUserDemoSingleDbTest] id:{}, res:{}", id, JsonUtils.toString(res));
        Assertions.assertNotNull(res, "res不能为空");
        Assertions.assertEquals(res.getSuccess(), Boolean.TRUE);
    }


    /**
     * 从数据源
     */
    @ParameterizedTest
    @DisplayName("从数据源")
    @ValueSource(longs = {1, 100, 102, 103, 104, 999})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.SLAVE_TEST), value = {"/ut/mock/sql/unit/controller/test/UserDemoControllerTest/testQueryUserDemoSingle.sql"})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.SLAVE_TEST), value = {"/ut/mock/sql/clean/user_demo_clean.sql"}, executionPhase = HSql.ExecutionPhase.AFTER_TEST_METHOD)
    public void testQueryUserDemoSingleDbTest1(long id) {
        BaseRes<UserDemoVO> res = userDemoController.queryUserDemoSingle(id);
        log.info("[UserDemoControllerTest#testQueryUserDemoSingleDbTest] id:{}, res:{}", id, JsonUtils.toString(res));
        Assertions.assertNotNull(res, "res不能为空");
        Assertions.assertEquals(res.getSuccess(), Boolean.TRUE);
    }


    /**
     * 主数据源
     */
    @ParameterizedTest
    @DisplayName("主数据源")
    @ValueSource(longs = {1, 100, 102, 103, 104, 999})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.MASTER_HEALER_JEAN), value = {"/ut/mock/sql/unit/controller/healerjean/UserDemoControllerTest/userDemos.sql"})
    @HSql(config = @SqlConfig(dataSource = DataSourceConstant.MASTER_HEALER_JEAN), value = {"/ut/mock/sql/clean/user_demo_clean.sql"}, executionPhase = HSql.ExecutionPhase.AFTER_TEST_METHOD)
    public void testQueryUserDemoSingleDbTest2(long id) {
        BaseRes<UserDemoVO> res = userDemoController.queryUserDemoSingle(id);
        log.info("[UserDemoControllerTest#testQueryUserDemoSingleDbTest] id:{}, res:{}", id, JsonUtils.toString(res));
        Assertions.assertNotNull(res, "res不能为空");
        Assertions.assertEquals(res.getSuccess(), Boolean.TRUE);
    }



}


ContactAuthor