Junit Mockito:使用mock作为参数从构造函数调用中获取ClassCastException

Junit Mockito:使用mock作为参数从构造函数调用中获取ClassCastException,junit,testng,mockito,powermock,Junit,Testng,Mockito,Powermock,我想要单元测试一个签名为 public oracle.sql.ARRAY methodA(java.sql.Connection connection) 连接对象是使用 Mockito.mock(Connection.class) 并在测试时传递给methodA oracle.sql.ARRAY有一个构造函数 new ARRAY(oracle.sql.ArrayDescriptor, Connection, Object) methodA具有获取ArrayDescriptor的逻辑。 它

我想要单元测试一个签名为

public oracle.sql.ARRAY  methodA(java.sql.Connection connection)
连接对象是使用

Mockito.mock(Connection.class)
并在测试时传递给methodA

oracle.sql.ARRAY有一个构造函数

new ARRAY(oracle.sql.ArrayDescriptor, Connection, Object)
methodA具有获取ArrayDescriptor的逻辑。 它还具有为该构造函数提供第三个参数的逻辑,但它将其作为对象数组提供

我模拟这两组逻辑,并传递一个模拟的ArrayDescriptor对象和一个模拟的对象数组。 所有这些模仿都是正确的

所以我的构造函数调用就像

new ARRAY(arrayDescriptorMock, connectionMock, objectMock)
此构造函数调用在作为测试的一部分执行时引发异常

java.lang.ClassCastException:$java.sql.Connection$$EnhancerByMockitoWithCGLIB$$2427854e 无法强制转换到oracle.jdbc.OracleConnection

为了避免这个错误,我多次尝试模拟这个构造函数调用。然而,每一项都证明是徒劳的。我正在为构造函数记录我的模拟代码

new ARRAY(oracle.sql.ArrayDescriptor, Connection, Object)
尝试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);
图例: ArrayDescriptor模拟:ArrayDescriptor的模拟

connectionMock:连接的模拟

objectArrayMock:对象数组的模拟,模拟代码为

  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应该拦截构造函数调用。这意味着它不允许执行真正的构造函数。假设它只返回一个数组类的模拟对象。为什么不这样呢?为什么它试图强制转换?

答案的开头是异常的简单消息

... cannot be cast to oracle.jdbc.OracleConnection
代码显示,oracle驱动程序中的
oracle.sql.ARRAY
对象不接受任何实现JDBC接口(如
java.sql.Connection
)的
对象(然后是mock)。这在某种程度上是任何连接器体系结构所期望的,包括JDBC,因为它遵循JCA原则

之所以会出现这种情况,是因为JCA实现中的对象需要在内部了解自己的对象并与之交互。
java.sql.Connection
接口只是该SPI(JDBC)客户端必须存在的最小可用契约

因此,考虑到这一事实,并且
oracle.sql.ARRAY
是oracle驱动程序类型,那么该对象需要一个内部
oracle.sql.Connection
才能正常运行。模拟一个
oracle.jdbc.OracleConnection
甚至都不会好,因为
ARRAY
可能会以比预期更多的方式与这种类型结合使用,最终会导致地狱般的固定物

通常我们,模拟主义者会说:“不要模拟你不拥有的类型。这是为了而不是模拟
oracle.sql.Connection
。但是在这个测试中,我不明白为什么有人会测试别人编写的代码,特别是JDBC驱动程序,但如果一个人实际上是驱动程序开发人员的话

如果您需要测试DAO或存储库是否使用
数组
,那么编写
集成测试
(使用真正的Oracle)将更合适


要回答这个问题,我想说的是,一定要去做一个IT。原因如下:

事实上,测试代码在某一点上涉及到专有类型。这些类型带有一个驱动程序,必须连接到一个真实的数据库才能提供一个连接来使用。我看不到一个简单的单元测试方法

  • 也许oracle驱动程序中有一些隐藏的类型可以提供帮助,但这只是一种可能,如果以后团队决定更改数据库,这会带来脆弱性,也会给重构带来困难
  • 或者您可以使用
    数组的模拟,但这会破坏此特定测试的目的

我必须补充一点,第一个原因是,当我的系统需要连接到另一个系统时,我总是编写集成测试。这有助于覆盖应用程序边界,包括持久性。我通常调用存储库的业务API(它们是带有面向业务API的DAO)Oracle或其他公司可以更改驱动程序的实现、删除类型等。我不必重写这些测试,只需重写实际的实现。

答案的开头是异常的简单消息

... cannot be cast to oracle.jdbc.OracleConnection
代码显示,oracle驱动程序中的
oracle.sql.ARRAY
对象不接受任何实现JDBC接口(如
java.sql.Connection
)的
object
(然后是mock)。这在某种程度上是任何连接器体系结构所期望的,包括JDBC,因为它遵循JCA原则

之所以会出现这种情况,是因为JCA实现中的对象需要知道自己的对象/与自己的对象进行内部交互。
java.sql.Connection
接口只是该SPI(JDBC)客户端必须存在的最小可用契约

因此,考虑到这一事实,并且
oracle.sql.ARRAY
是一种oracle驱动程序类型,那么这个对象需要一个内部
oracle.sql.Connection
才能正常工作。模拟
oracle.jdbc.OracleConnection
甚至不会好,因为
ARRAY
可能以多种方式与这种类型结合使用这是意料之中的,它最终将导致地狱般的固定物

我们,嘲弄者,通常会说:“不要嘲弄你没有的类型。这是为了而不是模仿
oracle.sql.Connection
。但是在这个测试中,我不明白为什么有人会测试一个由el编写的代码