专栏首页软件测试那些事策略模式案例II-看DBRider如何导入数据

策略模式案例II-看DBRider如何导入数据

本文介绍来自Database-Rider中关于数据库导入时的策略模式案例

首先来看一下使用案例

    @Test
    @DataSet(value = "datasets/yml/users.yml", strategy = SeedStrategy.CLEAN_INSERT)
    public void shouldSeedDataSetDisablingContraints() {
        User user = (User) EntityManagerProvider.em().createQuery("select u from User u where u.id = 1").getSingleResult();
        assertThat(user).isNotNull();
        assertThat(user.getId()).isEqualTo(1);
    }

从上述代码中可以了解到,@DataSet这个注解用于在测试用例执行前将来自value属性指定的数据文件users.yml插入到数据库中,通过strategy属性来指定数据库的插入方式为先清空数据库文件中涉及到的目标表,然后插入数据文件中提供的数据。

来看一下有哪些策略可供使用

public enum SeedStrategy {
    CLEAN_INSERT(DatabaseOperation.CLEAN_INSERT),
    TRUNCATE_INSERT(new CompositeOperation(DatabaseOperation.TRUNCATE_TABLE, DatabaseOperation.INSERT)),
    INSERT(DatabaseOperation.INSERT),
    REFRESH(DatabaseOperation.REFRESH),
    UPDATE(DatabaseOperation.UPDATE);
}

命名上看,各种操作还是非常容易理解的,这里就不展开说明了。不过其中的CompositeOperation说明这其中还使用了组合模式,这个可以在后续解读。

策略抽象类

策略模式通过一个接口或者抽象类来定义策略的运行方法。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.dbunit.operation;

import java.sql.SQLException;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;

public abstract class DatabaseOperation {
    public static final DatabaseOperation NONE = new DatabaseOperation.DummyOperation();
    public static final DatabaseOperation UPDATE = new UpdateOperation();
    public static final DatabaseOperation INSERT = new InsertOperation();
    public static final DatabaseOperation REFRESH = new RefreshOperation();
    public static final DatabaseOperation DELETE = new DeleteOperation();
    public static final DatabaseOperation DELETE_ALL = new DeleteAllOperation();
    public static final DatabaseOperation TRUNCATE_TABLE = new TruncateTableOperation();
    public static final DatabaseOperation CLEAN_INSERT;

    public DatabaseOperation() {
    }

    public static final DatabaseOperation TRANSACTION(DatabaseOperation operation) {
        return new TransactionOperation(operation);
    }

    public static final DatabaseOperation CLOSE_CONNECTION(DatabaseOperation operation) {
        return new CloseConnectionOperation(operation);
    }

    public abstract void execute(IDatabaseConnection var1, IDataSet var2) throws DatabaseUnitException, SQLException;

    static {
        CLEAN_INSERT = new CompositeOperation(DELETE_ALL, INSERT);
    }

    private static class DummyOperation extends DatabaseOperation {
        private DummyOperation() {
        }

        public void execute(IDatabaseConnection connection, IDataSet dataSet) {
        }
    }
}

在此案例中,使用了抽象类的方式,并提供了execute这个抽象方法。InsertOperation、UpdateOperation等具体策略只要继承并实现上述方法即可。

来看一下这个案例的类图(部分)

image.png

从类图上看,@DataSet注解使用到的数据库操作属于CUD部分,也就是从AbstractOperation这个抽象类继承而来的部分。

数据库导入操作类

策略模式中,一般都会有一个Context类来作为使用某种策略的类。 DBRider定义了一个DataSetExecutorImpl,用于实现对数据库的各项操作。其中用于处理@DataSet注解的方法是createDataSet。

@Override
    public void createDataSet(DataSetConfig dataSetConfig) {
 //......
     DatabaseOperation operation = getOperation(dataSetConfig);
 operation.execute(getRiderDataSource().getDBUnitConnection(), resultingDataSet);

这其中,通过getOperation方法来获取具体的DatebaseOperation策略类,并执行其中的execute方法。

获取策略的工厂方法

而在实际开发中为了将具体策略类的创建和使用者隔离,还会结合工厂模式。在DBRider这个案例中,只是简单地使用了getOperation方法。 具体代码如下:

private DatabaseOperation getOperation(DataSetConfig dataSetConfig) {
        SeedStrategy strategy = dataSetConfig.getstrategy();
        if (getRiderDataSource().getDBType() == RiderDataSource.DBType.MSSQL && dataSetConfig.isFillIdentityColumns()) {
            switch (strategy) {
                case INSERT:
                    return InsertIdentityOperation.INSERT;
                case REFRESH:
                    return InsertIdentityOperation.REFRESH;
                case CLEAN_INSERT:
                    return InsertIdentityOperation.CLEAN_INSERT;
                case TRUNCATE_INSERT:
                    return new CompositeOperation(DatabaseOperation.TRUNCATE_TABLE,
                            InsertIdentityOperation.INSERT);
            }
        }
        return strategy.getOperation();
    }

本文分享自微信公众号 - 软件测试那些事(antony-not-available),作者:风月同天测试人

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-10-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 规则引擎Easy-Rule极简入门

    Easy-Rule是一个轻量级的规则引擎,也非常容易上手。有了它,“满100减30,满200减60,最高减免xxx”, 程序员就不会因为规则实现错误公司被薅羊毛...

    Antony
  • 利用maven-git-commit-id-plugin实现版本与代码关联

    在一次关于devops平台的demo中,我们的运维同学提出一个需求,希望能够将发布的二进制文件和代码进行关联。当然,他们的希望是,能够点一下就能看到代码。(因为...

    Antony
  • 录制回放实现测试用例自由

    定义了 @Pointcut("execution(public * io.metersphere..controller...(..))") 这个切面,表...

    Antony
  • cocos2d-js 入门 (主要是HTML5)

    用户1258909
  • 系统进程管理工具Process Explorer

    系统进程往往是不少读者操作的“禁区”,其实借助一些功能强大的工具即可消除对该禁区的恐惧。Process Explorer就是一款系统进程管理工具,它不仅能方便地...

    张善友
  • 向silverlight传递自定义参数

    在silverlight往往还是有一些获取不到的东西,比如说客户机的ip等的数据.可以通过初始化sl时把参数传入sl中. 1.修改page类 public P...

    用户1172164
  • Python 函数的参数

    power(x,n),x和n就是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。

    py3study
  • 来Google演奏一曲,以从未有过的音色 (Demo+Paper+Code)

    若朴 发自 凹非寺 量子位 报道 | 公众号 QbitAI 上个月,Google公布了NSynth神经网络音频合成技术的细节。量子位在此前的报道里也有所提及。现...

    量子位
  • 聊聊jvm的StringTable及SymbolTable

    codecraft
  • React基础语法02-onKeyUp键盘事件

    3:继续实现 按回车键的时候,拿到值,首先监听KeyUp或者KeyDown事件,进行判断,当keyCode==13的时候,表示键盘按下,获取值。

    王小婷

扫码关注云+社区

领取腾讯云代金券