Mockito:从以mock为参数的构造函数调用中获取ClassCastException



我想单元测试一个签名为的方法

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);

相关内容

  • 没有找到相关文章

最新更新