Mockito JUnit测试中A类构造器父类转子类异常的处理方法
构造器强制转型引发的ClassCastException测试处理方案
异常根因
该场景下的异常本质是运行时类型不匹配:A类构造器要求传入的D类型参数,在运行时必须是子类B的实例,才能通过(B)d的强转校验。如果测试时直接mock一个原生的D类对象传入构造器,由于该对象运行时类型是D而非B,强转逻辑会直接抛出ClassCastException。
具体处理方式
- 优先匹配构造器的隐含类型约束,直接传入B类实例完成初始化
这是最符合代码设计逻辑的测试方式,不需要绕开构造器的强转逻辑:
如果B类本身存在复杂构造逻辑,可单独对B类的依赖做打桩处理,不需要刻意绕开B的类型层级。// 不要直接mock父类D,改为mock子类B的实例 B mockB = mock(B.class); // 直接传入B实例构造A对象,强转逻辑不会触发异常 A testA = new A(mockB); - 针对字段注入的RestApi依赖做单独注入
A类中的@Autowired private RestApi api是字段级注入,不需要依赖Spring容器完成初始化,在构造完合规的A实例后,可直接通过反射工具注入mock对象:A testA = new A(mock(B.class)); RestApi mockApi = mock(RestApi.class); // 直接将mock的api注入到A的私有字段中 ReflectionTestUtils.setField(testA, "api", mockApi); - 若需覆盖构造器的强转异常分支,直接断言预期异常即可
当测试目标是验证“传入非B类型D实例时,构造器的异常行为”时,不需要刻意规避异常,直接在测试用例中断言预期异常即可:@Test void constructor_WhenDNotInstanceOfB_ThrowsClassCastException() { // 构造一个非B实例的原生D对象 D plainD = mock(D.class); // 断言构造器抛出预期的类转换异常 assertThrows(ClassCastException.class, () -> new A(plainD)); }
设计提示
现有A类的构造器逻辑隐含了“传入的D必须是B实例”的约束,违反里氏替换原则:如果后续D类有其他子类实现,直接传入就会触发构造器异常。测试过程中对齐这个隐含约束,就能从根本上避免不必要的ClassCastException。
内容的提问来源于stack exchange,提问作者CodeGeek
相关产品推荐
相关产品推荐

