我想单元测试一个签名为的方法
public oracle.sql.ARRAY methodA(java.sql.Connection connection)
使用模拟连接对象
Mockito.mock(Connection.class)
并在测试时传递给方法A。
oracle.sql.ARRAY有一个构造函数
new ARRAY(oracle.sql.ArrayDescriptor, Connection, Object)
方法A具有用于获取ArrayDescriptor的逻辑。它还具有为该构造函数提供第三个参数的逻辑,但它将其作为对象的数组提供
我正在模拟这两组逻辑,并传递一个模拟ArrayDescriptor对象和一个模拟object数组。所有这些嘲弄都是正确的。
所以我的构造函数调用就像
new ARRAY(arrayDescriptorMock, connectionMock, objectMock)
此构造函数调用在作为测试的一部分执行时抛出异常
java.lang.ClassCastException:$java.sql.Connection$$EnhancerByMockitoWithCGLIB$$2427854e无法强制转换为oracle.jdbc.OracleConnection
为了避免这个错误,我已经多次尝试模拟这个构造函数调用。然而,每一次都被证明是徒劳的。我正在为构造函数记录我的模拟代码
尝试1
PowerMockito.whenNew(ARRAY.class).withParameterTypes(ArrayDescriptor.class, Connection.class, Object.class)
.withArguments(any(ArrayDescriptor.class), any(Connection.class), any(Object[].class))
.thenReturn(expectedArray);
尝试2
PowerMockito.whenNew(ARRAY.class).withArguments(arrayDescriptorMock,connectionMock,objectArrayMock).thenReturn(expectedArray);
图例:arrayDescriptorMock:ArrayDescriptor 的Mock
connectionMock:连接模型
objectArrayMock:对象数组的mock,模拟代码为
Object[] structArrayMock = new Object[2];
STRUCT obj1 = mock(STRUCT.class);
STRUCT obj2 = mock(STRUCT.class);
structArrayMock[0] = obj1;
structArrayMock[1] = obj2;
注意事项:测试中的方法有以下代码,我没有模拟
Object[] objArray = new Object[2];
我正在使用PowerMockito、Mockito和TestNG。然而,我相信这个问题和TestNG无关,所以JUNIT标签应该是好的。
请告知为什么会出现此ClassCastException,以及如何避免它?
编辑我还认为Mockito应该拦截构造函数调用。这意味着它不应该允许执行真正的构造函数。假设它只是返回ARRAY类的一个mock对象。为什么没有发生这种情况?为什么要尝试铸造?
答案的开头是异常的直接消息。
... cannot be cast to oracle.jdbc.OracleConnection
代码显示,来自oracle驱动程序的对象oracle.sql.ARRAY
不接受任何实现JDBC接口(如java.sql.Connection
)的Object
(,然后模拟)。这在任何连接器体系结构中都是意料之中的,JDBC也包括在内,因为它遵循JCA原则。
之所以会出现这种情况,是因为JCA实现中的对象需要在内部了解/与自己的对象交互。java.sql.Connection
接口只是该SPI(JDBC)的客户端必须存在的最小可用契约。
因此,考虑到这个事实,并且oracle.sql.ARRAY
是一个oracle驱动程序类型,那么这个对象需要一个内部oracle.sql.Connection
才能正常工作。模仿oracle.jdbc.OracleConnection
甚至都不好,因为ARRAY
可能以比预期更多的方式与这种类型结合使用,它最终会导致地狱般的固定。
通常,我们,模拟者说:"不要模拟你不拥有的类型。这是为了而不是模拟oracle.sql.Connection
。但在这个测试中,我不明白为什么有人会测试别人写的代码,尤其是JDBC驱动程序,但如果有人是驱动程序开发人员的话。
如果您需要测试DAO或存储库是否使用ARRAY
,那么编写Integration Tests
(使用真正的Oracle)会更合适。
为了回答这个意图,我会说肯定会选择IT。原因如下:
事实上,由于测试的代码在某些方面涉及专有类型。这些类型附带了一个驱动程序,该驱动程序必须连接到真实的数据库才能提供可使用的连接。,我看不出一种简单的单元测试方法
- 也许oracle驱动程序中有一些隐藏的类型可以提供帮助,但这只是一个可能,如果稍后团队决定更改数据库,这将带来脆弱性和重构困难
- 或者你可以使用
ARRAY
的模拟,但这会破坏这个特定测试的目的
我必须补充一点,第一个原因是当我的系统需要连接到另一个系统时,我总是编写集成测试的原因。IT有助于覆盖应用程序边界,包括持久性。我通常调用存储库的业务API(它们是具有面向业务的API的DAO),它们使用后面的任何数据存储来完成工作。Oracle或其他公司可以更改驱动程序的实现、删除类型等。我不必重写这些测试,只需要重写实际的实现。
oracle.sql.ARRAY
需要一个oracle.jdbc.OracleConnection
请参阅类ARRAY:中的代码
if(!(paramArrayDescriptor.getInternalConnection().isDescriptorSharable((oracle.jdbc.OracleConnection)paramConnection).physicalConnectionWithin())){throw new SQLException("无法构造ARRAY实例,无效连接");}
因此,当您试图提供PowerMockito模拟的java.sql.Connection
时,无法在oracle.jdbc.OracleConnection
中进行广播。
所以使用这个-
Connection conn = PowerMockito.mock(OracleConnection.class);