利用单元测试测试Ibatis动态语句

2019-04-26  本文已影响0人  nafoahnaw

背景

互联网这块因为数据量的关系,一般不允许太复杂的sql出现,所以sql语句本身逻辑并不太需要顾忌,但是如果ibatis动态语句语法写错了,编译也不报错,只能集成测试,或者上服务器晃一圈才能搞清有没有问题。但是第一,集成测试搭建成本太高,特别是对于互联网企业,各种数据库中间件封装的妈都不认识,不好mock,而且即使搭建起来了,集成测试的运行成本大家懂得,分钟级别,另一个就不说了,服务器部署跑一遍流程都够我在只狼里死20次了。
所以就想能不能单元测试直接把这块给测了。

思路

mock数据源相关的代码,手动组装SqlMapClientTemplate就ok了

相关代码(截取部分)

public class IbatisPersonDAOTest {

    private SqlMapClientTemplate sqlMapClientTemplate = new SqlMapClientTemplate();

    private IbatisPersonDAO ibatisPersonDAO = new IbatisPersonDAO();

    @Before
    public void setup() throws IOException {
        SqlMapConfigParser configParser = new SqlMapConfigParser();
        Resource resource = new ClassPathResource("sqlmap/sqlmap.xml");
        InputStreamReader reader = new InputStreamReader(resource.getInputStream());
        SqlMapClient sqlMapClient = configParser.parse(reader);
        sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
        DataSource mock = new MockDataSource();
        sqlMapClientTemplate.setDataSource(mock);
        sqlMapClientTemplate.afterPropertiesSet();
        ibatisPersonDAO.setSqlMapClientTemplate(sqlMapClientTemplate);
    }

    @Test
    public void testDeleteByIp() {
        List<String> idList = new ArrayList<>();
        idList.add("11");
        idList.add("22");
        idList.add("33");
        ibatisPersonDAO.deleteByID(idList);
    }
public class IbatisPersonDAO extends SqlMapClientDaoSupport implements PersonDAO {
        public int deleteByID(List idList) throws DataAccessException {
              return getSqlMapClientTemplate().delete("PERSON-DELETE-BY-ID", idList);
        }
}
public class MockConnection implements Connection {
    @Override
    public Statement createStatement() throws SQLException {
        return null;
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        PreparedStatement ps = new MockPrepareStatement();
        System.out.println(sql.trim());
        return ps;
    }
}
/**
 *
 * @author iminright-ali
 * @version $Id: MockDataSource.java, v 0.1 2019年04月26日 15:06 iminright-ali Exp $
 */
public class MockDataSource implements DataSource {
    @Override
    public Connection getConnection() throws SQLException {
        return new MockConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return new MockConnection();
    }
}
/**
 *
 * @author iminright-ali
 * @version $Id: MockPrepareStatement.java, v 0.1 2019年04月26日 15:47 iminright-ali Exp $
 */
public class MockPrepareStatement implements PreparedStatement {

    private List<Object> parameters = new ArrayList();

    @Override
    public ResultSet executeQuery() throws SQLException {
        return null;
    }

    @Override
    public int executeUpdate() throws SQLException {
        return 0;
    }

    @Override
    public void setNull(int parameterIndex, int sqlType) throws SQLException {
        this.parameters.add(parameterIndex - 1, (Object)null);
    }

    @Override
    public void setBoolean(int parameterIndex, boolean x) throws SQLException {
        this.parameters.add(parameterIndex - 1, x);
    }

    @Override
    public void setByte(int parameterIndex, byte x) throws SQLException {
        this.parameters.add(parameterIndex - 1, x);
    }

    @Override
    public void setShort(int parameterIndex, short x) throws SQLException {
        this.parameters.add(parameterIndex - 1, x);
    }

    @Override
    public void clearParameters() throws SQLException {
        this.parameters.clear();
    }
    
    @Override
    public boolean execute() throws SQLException {
        System.out.println(this.parameters);
        return false;
    }
}

扩展

通过MockPrepareStatement,MockConnection我们可以在测试用例的运行过程中捕获到各种各样的参数,然后可以做各种各样的Assert,比如参数个数,insert的时候参数的位置是否正确等等...

上一篇下一篇

猜你喜欢

热点阅读