开发者

mybatis单元测试过程(无需启动容器)

开发者 https://www.devze.com 2024-09-20 10:19 出处:网络 作者: wating1112
目录一、浅析相关类1 Configuration2 Executor3 XMLMapperBuilder二、单元测试1 生成mapper实例2 demo​​​​​​​总结一、浅析相关类
目录
  • 一、浅析相关类
    • 1 Configuration
    • 2 Executor
    • 3 XMLMapperBuilder
  • 二、单元测试
    • 1 生成mapper实例
    • 2 demo
  • ​​​​​​​总结

    一、浅析相关类

    1 Configuration

    MyBATis在启动时会取读取所有配置文件,然后加载到内存中,Configuration类就是承载整个配置的类。

    SqlSessionFactoryBuilder调用build方法创建SqlSessionFactory,而SqlSessionFactory需要Configuration配置中心提供创建的条件,在build方法中XMLConfigBuilder 将xml文件流进行初始化并parse返回Configuration,返回之前需要通过parseConfiguration来真正为Configuration设置信息,XPathParser负责将节点下的信息转换成XNode对象方便访问。

    2 Executor

    Executor是跟SqlSession绑定在一起的,每一个SqlSession都拥有一个新的Executor对象,由Configuration创建。

    Mybatis中所有的Mapper语句的执行都是通过Executor进行的,Executor是Mybatis的一个核心接口。

    从其定义的接口方法我们可以看出,对应的增删改语句是通过Executor接口的update方法进行的,查询是通过query方法进行的。

    虽然Executor接口的实现类有BaseExecutor和CachingExecutor,而BaseExecutor的子类又有SimpleExecutor、ReuseExecutor和BatchExecutor,但BaseExecutor是一个抽象类,其只实现了一些公共的封装,而把真正的核心实现都通过方法抽象出来给子类实现,如doUpdate()、doQuery();CachingExecutor只是在Executor的基础上加入了缓存的功能,底层还是通过Executor调用的,所以真正有作用的Executor只有SimpleExecutor、ReuseExecutor和BatchExecutor。

    它们都是自己实现的Executor核心功能,没有借助任何其它的Executor实现,它们是实现不同也就注定了它们的功能也是不一样的。

    3 XMLMapperBuilder

    mapper文件的解析依赖于XMLConfigBuilder的mapperElement方法来解析mapper文件。

    解析过程中实质是实例化一个XMLMapperBuilder对象,然后调用其parse方法,parse方法调用的configurationElement方法是真正mapper节点解析入口,包括sql解析,缓存,等。

    二、单元测试

    1 生成mapper实例

    运用以上相关类的功能,可以直接生成mapper的类实例。

    基于Java的编程思想,设计一个基类:

    BaseMapperTest:

    import org.apache.ibatis.binding.MapperProxyFactory;
    import org.apache.ibatis.builder.xml.XMLMapperBuilder;
    import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
    import org.apache.ibatis.executor.Executor;
    import org.ap编程ache.ibatis.session.Configuration;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.TransactionIsolationLevel;
    import org.apache.ibatis.session.defaults.DefaultSqlSession;
    import org.apache.ibatis.transaction.Transaction;
    import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
    import org.springframework.core.env.PropertySource;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.ResourcePropertySource;
    
    import java.lang.reflect.ParameterizedType;
    
    /**
     * @author: lyx
     */
    public class BaseMapperTest<T> {
        /**
         * mapper接口类(持久层接口)
         */
        private T mapper;
        /**
         * 数据库连接
         */
        private SqlSession sqlSession;
        /**
         * 执行
         */
        private static Executor executor;
        /**
         * 配置
         */
        private static Configuration configuration;
    
        static {
            try {
                //定义一个配置
                configuration = new Configuration();
                configuration.setCacheEnabled(false);
                configuration.setLazyLoadingEnabled(false);
                configuration.setAggressiveLazyLoading(true);
                configuration.setDefaultStatementTimeout(20);
                //读取测试环境数据库配置
                PropertySource propertySource = new ResourcePropertySource(new ClassPathResource("testdb.properties"));
                //设置数据库链接
                UnpooledDataSource dataSource = new UnpooledDataSource();
                dataSource.setDriver(propertySource.getProperty("driverClassName").toString());
                dataSource.setUrl(propertySource.getProperty("url").toString());
                dataSource.setUsername(propertySource.getProperty("username").toString());
                dataSource.setPassword(propertySource.getProperty("password").toString());
                //设置事务(测试设置事务不提交false)
                Transaction transaction = new JdbcTransaction(http://www.devze.comdataSource, TransactionIsolationLevel.READ_UNCOMMITTED, false);
                //设置执行
                executor = configuration.newExecutor(transaction);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public BaseMapperTest(String mapperName) {
            try {
                //解析mapper文件
                Resource mapperResource = new ClassPathResource(mapperName);
                XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperResource.getInputStream(), configuration, mapperResource.toStrihttp://www.devze.comng(), configuration.getSqlFragments());
                xmlMapperBwww.devze.comuilder.parsandroide();
                //直接实例化一个默认的sqlSession
                //是做单元测试,那么没必要通过SqlSessionFactoryBuilder构造SqlSessionFactory,再来获取SqlSession
                sqlSession = new DefaultSqlSession(configuration, executor, false);
                //将接口实例化成对象
                ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
                MapperProxyFactory<T> mapperProxyFactory = new MapperProxyFactory<>((Class<T>) pt.getActualTypeArguments()[0]);
                mapper = mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        /**
         * 返回mapper实例对象
         */
        public T getMapper() {
            return mapper;
        }
    }

    配置文件:testdb.properties

    driverClassName=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT&characterEncoding=utf8&useSSL=false&allowMultiQueries=true
    username=root
    password=root

    2 demo

    junit或者Testng单元测试都可以实现,下面给出一个junit测试的例子

    /**
     * @author lyx
     * 直接继承BaseMapperTest,并指定待持久层测试的接口即可
     */
    @RunWith(SpringRunner.class)
    public class BaseConfigDaoTest extends BaseMapperTest<BaseConfigDao> {
    
        public BaseConfigDaoTest() {
            super("mapper/BaseCodeConfigMapper.xml");
        }
    
        @Test
        public void selectListByCodeTest() {
            String code = "lyx";
            List<BaseConfigDTO> baseConfigList = super.getMapper().selectListByCode(code);
            Assert.assertTrue(baseConfigList.size() > 0);
        }
    
    }

    ​​​​​​​总结

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    关注公众号