单元测试时支持 H2 数据库中的 DB2 函数
Support DB2 functions in H2 database while unit testing
我们在生产中有一个 DB2 数据库,我们正在为测试设置一个 H2 内存数据库。我知道即使我们在 DB2 模式下配置 H2,也并非所有 DB2 功能都受支持。
我们如何对包含数据库特定功能但 H2 尚不支持的 SQL 进行单元测试?
如果我们开始编写 H2 特定的数据库服务,那么我们将结束编写不同层的功能代码。
不支持的功能
VARCHAR_FORMAT
H2配置
jdbc:h2:mem:test;MODE=DB2
H2版
1.4.188
Java 堆栈跟踪
Caused by: org.h2.jdbc.JdbcSQLException: Function "VARCHAR_FORMAT" not found; SQL statement:
select S.SCHEDULE_ID scheduleId, VARCHAR_FORMAT(S.START_DATE, 'DD-Mon-YYYY') startDate
from ScheduleSubscription S WITH UR [90022-182]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readJavaFunction(Parser.java:2333) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFunction(Parser.java:2385) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readTerm(Parser.java:2719) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFactor(Parser.java:2251) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readSum(Parser.java:2238) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readConcat(Parser.java:2208) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readCondition(Parser.java:2058) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readAnd(Parser.java:2030) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readExpression(Parser.java:2022) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimpleSelectPart(Parser.java:1934) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimple(Parser.java:1966) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSub(Parser.java:1860) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectUnion(Parser.java:1681) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelect(Parser.java:1669) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parsePrepared(Parser.java:433) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:305) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:277) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.prepareCommand(Parser.java:242) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareLocal(Session.java:446) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareCommand(Session.java:388) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1190) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:666) ~[h2-1.4.182.jar:1.4.182]
at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:295) ~[commons-dbcp-1.4.jar:1.4]
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:318) ~[commons-dbcp-1.4.jar:1.4]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke(ConnectionLogger.java:54) ~[mybatis-3.2.8.jar:3.2.8]
at $Proxy35.prepareStatement(Unknown Source) ~[na:na]
at org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement(PreparedStatementHandler.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:85) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:57) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102) ~[mybatis-3.2.8.jar:3.2.8]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
... 47 common frames omitted
创建一个名为 VARCHAR_FORMAT
的 H2 函数,并确保它 returns 至少对测试数据具有正确的值。
这当然需要为 H2 中尚不存在的每个功能付出努力,但这是非常可行的。测试也保持干净。
我们在生产中有一个 DB2 数据库,我们正在为测试设置一个 H2 内存数据库。我知道即使我们在 DB2 模式下配置 H2,也并非所有 DB2 功能都受支持。 我们如何对包含数据库特定功能但 H2 尚不支持的 SQL 进行单元测试?
如果我们开始编写 H2 特定的数据库服务,那么我们将结束编写不同层的功能代码。
不支持的功能
VARCHAR_FORMAT
H2配置
jdbc:h2:mem:test;MODE=DB2
H2版
1.4.188
Java 堆栈跟踪
Caused by: org.h2.jdbc.JdbcSQLException: Function "VARCHAR_FORMAT" not found; SQL statement:
select S.SCHEDULE_ID scheduleId, VARCHAR_FORMAT(S.START_DATE, 'DD-Mon-YYYY') startDate
from ScheduleSubscription S WITH UR [90022-182]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.182.jar:1.4.182]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readJavaFunction(Parser.java:2333) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFunction(Parser.java:2385) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readTerm(Parser.java:2719) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readFactor(Parser.java:2251) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readSum(Parser.java:2238) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readConcat(Parser.java:2208) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readCondition(Parser.java:2058) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readAnd(Parser.java:2030) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.readExpression(Parser.java:2022) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimpleSelectPart(Parser.java:1934) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSimple(Parser.java:1966) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectSub(Parser.java:1860) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelectUnion(Parser.java:1681) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parseSelect(Parser.java:1669) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parsePrepared(Parser.java:433) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:305) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.parse(Parser.java:277) ~[h2-1.4.182.jar:1.4.182]
at org.h2.command.Parser.prepareCommand(Parser.java:242) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareLocal(Session.java:446) ~[h2-1.4.182.jar:1.4.182]
at org.h2.engine.Session.prepareCommand(Session.java:388) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1190) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72) ~[h2-1.4.182.jar:1.4.182]
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:666) ~[h2-1.4.182.jar:1.4.182]
at org.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:295) ~[commons-dbcp-1.4.jar:1.4]
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:318) ~[commons-dbcp-1.4.jar:1.4]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke(ConnectionLogger.java:54) ~[mybatis-3.2.8.jar:3.2.8]
at $Proxy35.prepareStatement(Unknown Source) ~[na:na]
at org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement(PreparedStatementHandler.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.BaseStatementHandler.prepare(BaseStatementHandler.java:85) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare(RoutingStatementHandler.java:57) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:73) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:59) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:267) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:137) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:96) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:77) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:108) ~[mybatis-3.2.8.jar:3.2.8]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:102) ~[mybatis-3.2.8.jar:3.2.8]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_35]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_35]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_35]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_35]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
... 47 common frames omitted
创建一个名为 VARCHAR_FORMAT
的 H2 函数,并确保它 returns 至少对测试数据具有正确的值。
这当然需要为 H2 中尚不存在的每个功能付出努力,但这是非常可行的。测试也保持干净。