当前位置: 首页 > 知识库问答 >
问题:

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

柏正平
2023-03-14

我想对签名为的方法进行单元测试

public oracle.sql.ARRAY  methodA(java.sql.Connection connection)

连接对象使用

Mockito.mock(Connection.class)

并在测试时传递给methodA。

神谕sql。数组有一个构造函数

new ARRAY(oracle.sql.ArrayDescriptor, Connection, Object)

methodA具有获取ArrayDescriptor的html" target="_blank">逻辑。它还具有为该构造函数提供第三个参数的逻辑,但它将其作为对象数组提供

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

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

new ARRAY(arrayDescriptorMock, connectionMock, objectMock)

当作为测试的一部分执行时,这个构造函数调用抛出一个异常

JAVAlang.ClassCastException:$java。sql。无法将连接$$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);

图例:ArrayDescriptor模拟:ArrayDescriptor的模拟

连接的模拟

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

共有2个答案

郭璞
2023-03-14

oracle。sql。数组需要一个oracle。jdbc。OracleConnection请参见类数组中的代码:

if(!(paramArrayDescriptor.getInternalConnection()。isDescriptorSharable(((oracle.jdbc.OracleConnection)paramConnection)。physicalConnectionWithin()){抛出新的SQLException(“无法构造数组实例,连接无效”);}

因此,当您试图提供java时。sql。连接由PowerMockito模拟,不能在oracle中铸造。jdbc。OracleConnection

所以用这个-

  Connection conn = PowerMockito.mock(OracleConnection.class);
黄弘盛
2023-03-14

答案的开头是异常的直接消息。

... cannot be cast to oracle.jdbc.OracleConnection

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

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

鉴于这一事实和甲骨文。sql。ARRAY是oracle驱动程序类型,那么这个对象需要一个内部的oracle。sql。连接以正常工作。模仿oracle。jdbc。OracleConnection甚至不会很好,因为阵列可能以比预期更多的方式与这种类型结合使用,它最终将导致地狱般的固定装置。

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

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

为了回答这个意图,我会说绝对去做一个信息技术。原因如下:

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

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

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

 类似资料:
  • 我有一个 Scala 类,它使用 Apache Spark 中的 MR 作业返回输入类型 IN 的最大值。如果我从Scala调用它,这个类工作正常,它的工作原理如下: 现在我想让它也可以从java中调用,但是我在传递隐式参数时遇到了一些困难。我知道隐式参数可以通过在Java中将它们追加到参数列表中来传递,但是隐式参数是在Scala中。因此,我正在努力做到以下几点: 然后可以从java调用: 我尝试

  • 问题内容: 我想将构造函数模拟为方法。 在我的测试中,我想做这样的事情: 但是给我这个 错误 知道为什么吗? 问题答案: 您可以使用PowerMock模拟构造函数。 如果由于某种原因而无法使用PowerMock,则最可行的解决方案是将工厂注入到包含此方法的任何类中。然后,您将使用工厂创建对象并模拟工厂。

  • 问题内容: 我想为MySortedSet调用一个构造函数,该构造函数将Comparator c作为参数。我该如何修改呢? 问题答案: 如果要传递其他捕获的值作为参数,则不能使用方法引用。您将不得不使用lambda表达式来代替: =>

  • 我正试图用BlueJ完成一项为uni完成的任务,但我在第一个障碍上遇到了障碍。 在赋值中,我们得到了一个类,以及该类的构造函数、方法和参数的名称。我们不允许更改这些,因为赋值部分地由测试单元标记(或类似的东西)。 该类的一个构造函数如下所示 我已经(部分)完成了 我不明白的是为什么-为什么他们使用作为构造函数的参数?这样做有什么好处? (我想这样做肯定有好处(如果没有,功能就不会存在),但我不明白

  • 问题内容: 根据Node.js手册: 如果您希望模块导出的根是一个函数(例如构造函数),或者想一次导出一个完整的对象而不是一次构建一个对象,则将其分配给module.exports而不是export 。 给出的示例是: 并像这样使用: 我的问题:为什么示例不使用正方形作为对象?以下内容是否有效,是否会使示例更加“面向对象”? 问题答案: CommonJS模块允许两种方法来定义导出的属性。无论哪种情

  • 我有一个带有私有构造函数的单例类,我想为此编写单元测试。 如何使用mockito框架模拟具有私有构造函数的类。 谢谢