背景
互联网这块因为数据量的关系,一般不允许太复杂的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的时候参数的位置是否正确等等...
网友评论