单元测试 - 集成H2 Dao测测试

SpringBoot 2.7、Mybatis plus、H2

1. pom引入h2


    com.h2database
    h2
    2.1.214

2. 配置h2数据源 & mapper路径

spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:ut_test;DB_CLOSE_DELAY=-1;MODE=MySQL
    username:
    password:
  sql:
    init:
      schema-locations:
        - classpath:schema.sql
      data-locations:
        - classpath:data.sql


mybatis-plus:
  mapper-locations: classpath*:mapper/*Mapper.xml
  global-config:
    db-config:
      logic-delete-field: IsDeleted
      logic-delete-value: 1
      logic-not-delete-value: 0

3. 准备单测环境

import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class) //启动SpringRunner运行单测
@SpringBootTest(classes = { // 指定需要加载到Spring容器中的类
        DataSourceAutoConfiguration.class, // 数据源自动装配类,装配数据源DataSource
        MybatisPlusAutoConfiguration.class, // mybatisPlus自动装配类,SqlSession相关Bean
        SqlInitializationAutoConfiguration.class,// sql初始化自动装配类,以运行sql初始化文件(eg. schema.sql)
        RepoTestConfig.class // 自定义配置类,指定mapper扫描路径
})
public class BaseTest {

}



import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.xx.mapper"}) // 指定mapper类扫描位置
public class RepoTestConfig {
}


// 具体测试类
public class MapperTest extends BaseTest {
    @Autowired
    TestgMapper testgMapper ;

    @Test
    public void selectByKey() {
        testgMapper .selectByKey("");
    }
}

4. Sql init

   schema.sql

CREATE TABLE `xx` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `K` varchar(255) NOT NULL COMMENT 'key',
  `V` text COMMENT 'value',
  `Remark` varchar(255) DEFAULT NULL,
  `CreatedBy` int(11) DEFAULT '0' COMMENT '0-system',
  `CreatedDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `UpdatedBy` int(11) DEFAULT '0' COMMENT '0-system',
  `UpdatedDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `IsDeleted` bit(1) DEFAULT '0',
  PRIMARY KEY (`Id`),
  UNIQUE KEY `Idx_K` (`K`)
);

   data.sql (看需求)

insert into ...

5. 考虑点&遇到的问题

        5.1 Spring容器需要加载哪些类,如何加载

        方式一,通过@SpringBootApplication启动容器&加载Bean

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = {"com.xx.mapper"})
public class UTApplication {
    public static void main(String[] args) {
            SpringApplication.run(UTApplication.class, args);
    }
}

import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = UTApplication.class)
public class BaseTest {

}

pros:简单,几个注解简单配置搞定,不用去关心具体需要配置的Bean(因为所有用到的用不到的都被引入了)

cons:@SpringBootApplication注解会开启自动装配,一些非必要的类也会被装配到单测的Spring环境中

        方式二 按需装配 

@RunWith(SpringRunner.class) //启动SpringRunner运行单测
@SpringBootTest(classes = { // 指定需要加载到Spring容器中的类
        DataSourceAutoConfiguration.class, // 数据源自动装配类,装配数据源DataSource
        MybatisPlusAutoConfiguration.class, // mybatisPlus自动装配类,SqlSession相关Bean
        SqlInitializationAutoConfiguration.class,// sql初始化自动装配类,以运行sql初始化文件(eg. schema.sql)
        RepoTestConfig.class // 自定义配置类,指定mapper扫描路径
})
public class BaseTest {

}

        pros:按需加载,用到哪些加载哪些

        cons:需要花些时间确定需要加载的Bean,最后确定如上图        

        5.2 问题&解决        

        按照spring.datasource.schema: schema.sql的方式配置sql初始化脚本,以@SpringBootApplication方式启动容器没问题,改成按需装配后初始化脚本schema.sql 未执行

spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:ut_test;DB_CLOSE_DELAY=-1;MODE=MySQL
    username:
    password:
    schema : schema.sql // 一开始错误的配置方式

  sql:
    init:
      schema-locations:
        - classpath:schema.sql // 修正后正确的配置方式

排查一番后发现,原因是按需加载方式未将负责初始化sql的sql Initializer加载到容器中,所以就做不了这事,经过排查,此类是SqlInitializationAutoConfiguration,将其指定加载到容器中即可。

而@SpringBootApplication方式默认是装配了该类的,所以可行。

并且在排查过程中发现,sql Initializer默认会去找spring.sql.init下指定的sql文件,如果找不到,再去加载了classpath下的schema.sql。所以之前schema: schema.sql指定的sql文件能被正确加载,是因为他被命名为schemal.sql并且被放在了classpath下,并不是因为schema: schema.sql的配置,换个名就不行了。也就是说不需要配置schema: schema.sql, 直接在resource下放一个名叫schema.sql的文件,都能正常工作。正确的方式是通过spring.sql.init方式指定

排查过程

通过查看配置文件中schema-locations的引用位置,定位到SqlInitializationProperties

单元测试 - 集成H2 Dao测测试_第1张图片

 通过对SqlInitializationProperties的引用加上合理猜测定位SettingsCreator

单元测试 - 集成H2 Dao测测试_第2张图片

 根据引用定位SqlDataSourceScriptDatabaseInitializer

单元测试 - 集成H2 Dao测测试_第3张图片

 再看是谁负责加载SqlDataSourceScriptDatabaseInitializer. nice,that's DataSourceInitializationConfiguration,也就是说只要把DataSourceInitializationConfiguration加载进容器,就可以了。但是,发现这个类是包私有的,外部不能引用,好吧,那就再网上找一级,谁来负责加载DataSourceInitializationConfiguration

单元测试 - 集成H2 Dao测测试_第4张图片

SqlInitializationAutoConfiguration,就是他,配置到容器即可

单元测试 - 集成H2 Dao测测试_第5张图片

 

@SpringBootTest(classes = {SqlInitializationAutoConfiguration.class})

 

 

你可能感兴趣的:(java,单元测试)