亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

對(duì)dbunit進(jìn)行mybatis DAO層Excel單元測(cè)試(必看篇)

 更新時(shí)間:2017年05月23日 08:57:28   投稿:jingxian  
下面小編就為大家?guī)?lái)一篇對(duì)dbunit進(jìn)行mybatis DAO層Excel單元測(cè)試(必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

DAO層測(cè)試難點(diǎn)

可重復(fù)性,每次運(yùn)行單元測(cè)試,得到的數(shù)據(jù)是重復(fù)的

獨(dú)立性,測(cè)試數(shù)據(jù)與實(shí)際數(shù)據(jù)相互獨(dú)立

數(shù)據(jù)庫(kù)中臟數(shù)據(jù)預(yù)處理

不能給數(shù)據(jù)庫(kù)中數(shù)據(jù)帶來(lái)變化

DAO層測(cè)試方法

使用內(nèi)存數(shù)據(jù)庫(kù),如H2。優(yōu)點(diǎn):無(wú)需清空無(wú)關(guān)數(shù)據(jù);缺點(diǎn):?jiǎn)卧獪y(cè)試中需要進(jìn)行數(shù)據(jù)庫(kù)初始化過(guò)程,如果初始化過(guò)程復(fù)雜,單元測(cè)試工作量增大

使用dbunit。優(yōu)點(diǎn):數(shù)據(jù)庫(kù)初始化簡(jiǎn)單,大大減輕單元測(cè)試工作量;缺點(diǎn):目前官方提供jar包只支持xml格式文件,需要自己開發(fā)Excel格式文件

基于dbunit進(jìn)行DAO單元測(cè)試

應(yīng)用環(huán)境:Spring、Mybatis、MySql、Excel

配置文件

1. pom.xml

引入jar包,unitils整合了dbunit,database,spring,io等模塊

<dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-core</artifactId>
    <version>3.4.2</version>
  </dependency>
  <dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-dbunit</artifactId>
    <version>3.4.2</version>
  </dependency>
  <dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-io</artifactId>
    <version>3.4.2</version>
  </dependency>
  <dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-database</artifactId>
    <version>3.4.2</version>
  </dependency>
  <dependency>
    <groupId>org.unitils</groupId>
    <artifactId>unitils-spring</artifactId>
    <version>3.4.2</version>
  </dependency>
  <dependency>
    <groupId>org.dbunit</groupId>
    <artifactId>dbunit</artifactId>
    <version>2.5.3</version>
  </dependency>

配置maven對(duì)resourcew文件過(guò)濾規(guī)則,如果不過(guò)濾maven會(huì)對(duì)resource文件重編碼,導(dǎo)致Excel文件被破壞

<resources>
    <resource>
      <directory>src/test/resources</directory>
      <includes>
        <include>**/*.*</include>
      </includes>
      <filtering>false</filtering>
    </resource>
  </resources>

2. unitils.properties

在測(cè)試源碼根目錄中創(chuàng)建一個(gè)項(xiàng)目級(jí)別的unitils.properties配置文件,主要用于配置自定義拓展模塊,數(shù)據(jù)加載等相關(guān)信息

#啟用unitils所需模塊
unitils.modules=database,dbunit

#自定義擴(kuò)展模塊,加載Excel文件,默認(rèn)拓展模塊org.unitils.dbunit.DbUnitModule支持xml
unitils.module.dbunit.className=org.agoura.myunit.module.MyDbUnitModule

#配置數(shù)據(jù)庫(kù)連接
database.driverClassName=com.mysql.jdbc.Driver
database.url=jdbc:mysql://127.0.0.1:3306/teams?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=utf-8
database.userName=root
database.password=agoura
#配置為數(shù)據(jù)庫(kù)名稱
database.schemaNames=teams
#配置數(shù)據(jù)庫(kù)方言
database.dialect=mysql

#需設(shè)置false,否則我們的測(cè)試函數(shù)只有在執(zhí)行完函數(shù)體后,才將數(shù)據(jù)插入的數(shù)據(jù)表中
unitils.module.database.runAfter=false

#配置數(shù)據(jù)庫(kù)維護(hù)策略.請(qǐng)注意下面這段描述
# If set to true, the DBMaintainer will be used to update the unit test database schema. This is done once for each
# test run, when creating the DataSource that provides access to the unit test database.
updateDataBaseSchema.enabled=true

#配置數(shù)據(jù)庫(kù)表創(chuàng)建策略,是否自動(dòng)建表以及建表sql腳本存放目錄
dbMaintainer.autoCreateExecutedScriptsTable=true
dbMaintainer.keepRetryingAfterError.enabled=true
dbMaintainer.script.locations=src/main/resources/dbscripts
#dbMaintainer.script.fileExtensions=sql

#數(shù)據(jù)集加載策略
#CleanInsertLoadStrategy:先刪除dateSet中有關(guān)表的數(shù)據(jù),然后再插入數(shù)據(jù)
#InsertLoadStrategy:只插入數(shù)據(jù)
#RefreshLoadStrategy:有同樣key的數(shù)據(jù)更新,沒有的插入
#UpdateLoadStrategy:有同樣key的數(shù)據(jù)更新,沒有的不做任何操作
DbUnitModule.DataSet.loadStrategy.default=org.unitils.dbunit.datasetloadstrategy.impl.CleanInsertLoadStrategy

#配置數(shù)據(jù)集工廠,自定義
DbUnitModule.DataSet.factory.default=org.agoura.myunit.utils.MultiSchemaXlsDataSetFactory
DbUnitModule.ExpectedDataSet.factory.default=org.agoura.myunit.utils.MultiSchemaXlsDataSetFactory

#配置事務(wù)策略 commit、rollback 和disabled;或者在代碼的方法上標(biāo)記@Transactional(value=TransactionMode.ROLLBACK)
#commit 是單元測(cè)試方法過(guò)后提交事務(wù)
#rollback 是回滾事務(wù)
#disabled 是沒有事務(wù),默認(rèn)情況下,事務(wù)管理是disabled
DatabaseModule.Transactional.value.default=commit

#配置數(shù)據(jù)集結(jié)構(gòu)模式XSD生成路徑,可以自定義目錄,但不能為空
dataSetStructureGenerator.xsd.dirName=src/main/resources/xsd
dbMaintainer.generateDataSetStructure.enabled=true

#文件相對(duì)路徑是否是測(cè)試類文件路徑,false表示resource根目錄
dbUnit.datasetresolver.prefixWithPackageName=false

3. spring-mybatis-unitils.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.1.xsd">

  <context:component-scan base-package="com.agoura.agoura"/>

  <context:property-placeholder location="classpath:jdbc_dbcp.properties"/>
  <!--<util:properties id="jdbc_dbcp" />-->

  <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean"/>

  <!-- spring和MyBatis整合,不需要mybatis的配置映射文件 -->
  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <!-- 自動(dòng)掃描mapping.xml文件 -->
    <property name="mapperLocations" value="classpath*:com/agoura/agoura/mapper/xml/*.xml"></property>
  </bean>

  <!-- DAO接口所在包名,Spring會(huì)自動(dòng)查找其下的類 -->
  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.agoura.agoura.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
  </bean>

  <!-- (事務(wù)管理)transaction manager, use JtaTransactionManager for global tx -->
  <bean id="transactionManager"
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
  </bean>
</beans>

dbunit執(zhí)行流程

dbunit通過(guò)@DataSet注解讀取模擬數(shù)據(jù)Excel文件,流程如下:

Excel文件 --> @DataSet --> DbUnitModule --> DataSetFactory --> 數(shù)據(jù)庫(kù)(MySql)

@DataSet:將指定路徑下Excel文件加載到DbUnitModule中

DbUnitModule:對(duì)傳入文件進(jìn)行預(yù)處理,源代碼中對(duì)傳入的xml文件copy一份臨時(shí)文件,并將臨時(shí)文件交給DataSetFactory處理,處理完后再刪除臨時(shí)文件

DataSetFactory:將讀取的Excel數(shù)據(jù)轉(zhuǎn)換為MultiSchemaDataSet,準(zhǔn)備放入數(shù)據(jù)庫(kù)中

由于原代碼DbUnitModule中只有對(duì)xml文件的預(yù)處理,而我們是要對(duì)Excel文件進(jìn)行預(yù)處理,所以需要對(duì)DbUnitModule進(jìn)行重寫。重寫內(nèi)容為:完善DbUnitDatabaseConnection連接;針對(duì)Excel文件,修改預(yù)處理實(shí)現(xiàn);修改文件處理后續(xù)操作。示例如下:

import org.dbunit.database.DatabaseConfig;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.ext.mysql.MySqlMetadataHandler;
import org.unitils.core.UnitilsException;
import org.unitils.dbmaintainer.locator.ClassPathDataLocator;
import org.unitils.dbmaintainer.locator.resourcepickingstrategie.ResourcePickingStrategie;
import org.unitils.dbunit.DbUnitModule;
import org.unitils.dbunit.datasetfactory.DataSetFactory;
import org.unitils.dbunit.util.DbUnitDatabaseConnection;
import org.unitils.dbunit.util.MultiSchemaDataSet;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class MyDbUnitModule extends DbUnitModule {

  //完善DbUnitDatabaseConnection連接信息
  @Override
  public DbUnitDatabaseConnection getDbUnitDatabaseConnection(final String schemaName) {
    DbUnitDatabaseConnection result = dbUnitDatabaseConnections.get(schemaName);
    if (result != null) {
      return result;
    }

    result = super.getDbUnitDatabaseConnection(schemaName);

    result.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory());
    result.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
    return result;
  }

  //Excel預(yù)處理操作,將@DataSet注釋讀取的文件返回給DataSetFactory進(jìn)行處理
  @Override
  protected File handleDataSetResource(ClassPathDataLocator locator, String nameResource, ResourcePickingStrategie strategy, Class<?> testClass) {
    String cloneResource = new String(nameResource);
    String packageName = testClass.getPackage() != null?testClass.getPackage().getName():"";
    String tempName = "";
    if(cloneResource.startsWith(packageName.replace(".", "/"))) {
      cloneResource = tempName = cloneResource.substring(packageName.length());
    } else if(cloneResource.startsWith(packageName)) {
      cloneResource = tempName = cloneResource.substring(packageName.length() + 1);
    } else {
      tempName = cloneResource;
    }

    InputStream in = locator.getDataResource(packageName.replace(".", "/") + "/" + tempName, strategy);
    File resolvedFile = null;
    if(in == null) {
      resolvedFile = this.getDataSetResolver().resolve(testClass, cloneResource);
      if(resolvedFile == null) {
        throw new UnitilsException("DataSetResource file with name '" + nameResource + "' cannot be found");
      }
    }

    return resolvedFile;
  }

  //調(diào)用DataSetFactory.createDataSet()向數(shù)據(jù)庫(kù)中注入Excel數(shù)據(jù)后,直接返回DataSet,不對(duì)DataSet執(zhí)行清零操作
  @Override
  protected MultiSchemaDataSet getDataSet(Class<?> testClass, String[] dataSetFileNames, DataSetFactory dataSetFactory) {
    List<File> dataSetFiles = new ArrayList<File>();

    ResourcePickingStrategie resourcePickingStrategie = getResourcePickingStrategie();

    for (String dataSetFileName : dataSetFileNames) {
      File dataSetFile = handleDataSetResource(new ClassPathDataLocator(), dataSetFileName, resourcePickingStrategie, testClass);
      dataSetFiles.add(dataSetFile);
    }

    MultiSchemaDataSet dataSet = dataSetFactory.createDataSet(dataSetFiles.toArray(new File[dataSetFiles.size()]));
    return dataSet;
  }
}

拓展模塊DbUnitModule重寫完后,由于官方版本中DataSetFactory只對(duì)xml文件進(jìn)行處理,為了能處理Excel文件,需要對(duì)DataSetFactory進(jìn)行重寫。示例如下:

import org.unitils.core.UnitilsException;
import org.unitils.dbunit.datasetfactory.DataSetFactory;
import org.unitils.dbunit.util.MultiSchemaDataSet;

import java.io.File;
import java.util.*;

public class MultiSchemaXlsDataSetFactory implements DataSetFactory {
  protected String defaultSchemaName;

  public void init(Properties configuration, String s) {
    this.defaultSchemaName = s;
  }

  public MultiSchemaDataSet createDataSet(File... dataSetFiles) {
    try {
      MultiSchemaXlsDataSetReader xlsDataSetReader = new MultiSchemaXlsDataSetReader(defaultSchemaName);
      return xlsDataSetReader.readDataSetXls(dataSetFiles);
    } catch (Exception e) {
      throw new UnitilsException("創(chuàng)建數(shù)據(jù)集失?。? + Arrays.toString(dataSetFiles), e);
    }
  }

  public String getDataSetFileExtension() {
    return "xls";
  }
}

createDataSet()為自定義的數(shù)據(jù)集工廠MultiSchemaXlsDataSetFactory中的核心方法,主要是讀取傳入的Excel文件,將讀取數(shù)據(jù)寫入MutiSchemaXlsDataSet中。MultiSchemaXlsDataSetReader通過(guò)POI實(shí)現(xiàn)了讀取Excel數(shù)據(jù)功能,可以同時(shí)讀取多個(gè)數(shù)據(jù)集,也即多個(gè)模擬數(shù)據(jù)庫(kù)數(shù)據(jù)。

import org.dbunit.database.AmbiguousTableNameException;
import org.dbunit.dataset.DefaultDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.excel.XlsDataSet;
import org.unitils.core.UnitilsException;
import org.unitils.dbunit.util.MultiSchemaDataSet;

import java.io.File;
import java.io.FileInputStream;
import java.util.*;

public class MultiSchemaXlsDataSetReader {
  private String pattern = ".";
  private String defaultSchemaName;

  public MultiSchemaXlsDataSetReader(String defaultSchemaName) {
    this.defaultSchemaName = defaultSchemaName;
  }

  public MultiSchemaDataSet readDataSetXls(File... dataSetFiles) {
    try {
      Map<String, List<ITable>> tbMap = getTables(dataSetFiles);
      MultiSchemaDataSet dataSets = new MultiSchemaDataSet();

      for (Map.Entry<String, List<ITable>> entry : tbMap.entrySet()) {
        List<ITable> tables = entry.getValue();
        try {
          DefaultDataSet ds = new DefaultDataSet(tables.toArray(new ITable[]{}));
          dataSets.setDataSetForSchema(entry.getKey(), ds);
        } catch (AmbiguousTableNameException e) {
          throw new UnitilsException("構(gòu)造DataSet失??!", e);
        }
      }
      return dataSets;
    } catch (Exception e) {
      throw new UnitilsException("解析Excel文件出錯(cuò):", e);
    }
  }

  private Map<String, List<ITable>> getTables(File... dataSetFiles) {
    Map<String, List<ITable>> tableMap = new HashMap<>();
    // 需要根據(jù)schema把Table重新組合一下
    try {
      String schema, tableName;
      for (File file : dataSetFiles) {
        IDataSet dataSet = new XlsDataSet(new FileInputStream(file));
        String[] tableNames = dataSet.getTableNames();
        for (String tn : tableNames) {
          String[] temp = tn.split(pattern);
          if (temp.length == 2) {
            schema = temp[0];
            tableName = temp[1];
          } else {
            schema = this.defaultSchemaName;
            tableName = tn;
          }

          ITable table = dataSet.getTable(tn);
          if (!tableMap.containsKey(schema)) {
            tableMap.put(schema, new ArrayList<ITable>());
          }
          tableMap.get(schema).add(new XslTableWrapper(tableName, table));
        }
      }
    } catch (Exception e) {
      throw new UnitilsException("Unable to create DbUnit dataset for data set files: " + Arrays.toString(dataSetFiles), e);
    }
    return tableMap;
  }
}

到此,unitils重寫及配置完畢,下面進(jìn)行測(cè)試。

測(cè)試示例

被測(cè)試DAO層代碼:

public interface MembersMapper {
  int deleteByPrimaryKey(Integer id);

  int insert(Members record);

  Members selectByPrimaryKey(Integer id);

  int updateByPrimaryKey(Members record);
}

測(cè)試類文件:

import com.agoura.entity.Members;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.unitils.UnitilsJUnit4;
import org.unitils.UnitilsJUnit4TestClassRunner;
import org.unitils.dbunit.annotation.DataSet;

import static org.junit.Assert.assertNotNull;

@RunWith(UnitilsJUnit4TestClassRunner.class)
@ContextConfiguration(locations = {"classpath*:spring-*.xml"})
public class MembersMapperTest extends UnitilsJUnit4 {

  private MembersMapper membersMapper;
  private static ApplicationContext ctx;

  @BeforeClass
  public static void setUpBeforeClass() {
    ctx = new ClassPathXmlApplicationContext("classpath*:spring-mybatis-unitils.xml");
  }

  @Before
  public void setUp() {
    membersMapper = (MembersMapper) ctx.getBean("membersMapper");
  }

  @Test
  @DataSet(value = {"test.xls"})   //test.xlsx
  public void testSelectByPrimaryKey() throws Exception {
    Members member = membersMapper.selectByPrimaryKey(3);
    System.out.println(member);
    assertEquals("王五", member.getName());
  }
}

@DataSet加載Excel文件,既可以加載 .xls文件,也可以加載 .xlsx文件。

.xls示例如下:

應(yīng)數(shù)據(jù)庫(kù)表名,字段必須和數(shù)據(jù)庫(kù)表字段一一對(duì)應(yīng)。

測(cè)試結(jié)果

以上這篇對(duì)dbunit進(jìn)行mybatis DAO層Excel單元測(cè)試(必看篇)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java8中Stream?API的peek()方法詳解及需要注意的坑

    Java8中Stream?API的peek()方法詳解及需要注意的坑

    這篇文章主要給大家介紹了關(guān)于Java8中Stream?API的peek()方法詳解及需要注意的坑,Java 中的 peek 方法是 Java 8 中的 Stream API 中的一個(gè)方法,它屬于中間操作,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • Java Home變量的詳細(xì)配置操作步驟

    Java Home變量的詳細(xì)配置操作步驟

    用到Java項(xiàng)目的時(shí)候,有時(shí)候要用到Java_home,這個(gè)需要在系統(tǒng)配置中配置一下,如何操作呢?以下為詳細(xì)的圖文步驟,感興趣的朋友跟隨小編一起看看吧
    2023-11-11
  • 分布式系統(tǒng)中的降級(jí)熔斷設(shè)計(jì)問題面試

    分布式系統(tǒng)中的降級(jí)熔斷設(shè)計(jì)問題面試

    這篇文章主要為大家介紹了分布式系統(tǒng)中的降級(jí)熔斷設(shè)計(jì)問題面試解答,有需要的朋友可以借鑒參考下,希望能有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 使用ObjectMapper把Json轉(zhuǎn)換為復(fù)雜的實(shí)體類

    使用ObjectMapper把Json轉(zhuǎn)換為復(fù)雜的實(shí)體類

    這篇文章主要介紹了使用ObjectMapper把Json轉(zhuǎn)換為復(fù)雜的實(shí)體類操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Spring boot基于ScheduledFuture實(shí)現(xiàn)定時(shí)任務(wù)

    Spring boot基于ScheduledFuture實(shí)現(xiàn)定時(shí)任務(wù)

    這篇文章主要介紹了Spring boot基于ScheduledFuture實(shí)現(xiàn)定時(shí)任務(wù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 圖片疊加效果Java代碼實(shí)現(xiàn)

    圖片疊加效果Java代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了圖片疊加效果Java代碼實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • 使用restTemplate遠(yuǎn)程調(diào)controller路徑取數(shù)據(jù)

    使用restTemplate遠(yuǎn)程調(diào)controller路徑取數(shù)據(jù)

    這篇文章主要介紹了使用restTemplate遠(yuǎn)程調(diào)controller路徑取數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • SpringBoot+Response如何統(tǒng)一返回result結(jié)果集

    SpringBoot+Response如何統(tǒng)一返回result結(jié)果集

    這篇文章主要介紹了SpringBoot+Response如何統(tǒng)一返回result結(jié)果集,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 淺談Java中spring 線程異步執(zhí)行

    淺談Java中spring 線程異步執(zhí)行

    這篇文章主要介紹了淺談spring 線程異步執(zhí)行,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java實(shí)現(xiàn)三子棋小游戲

    Java實(shí)現(xiàn)三子棋小游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)三子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評(píng)論