如何Mock依赖类内初始化的私有final客户端方法?Drools场景
解决方案
1. 重构类A实现依赖注入(推荐)
直接修改类A的构造逻辑,允许外部传入B实例,从根源上解耦A和B的硬依赖:
class A { private final B b; // 保留原有构造函数兼容旧代码 public A(String x, String y) { this(new B(x, y)); } // 新增构造函数用于注入B实例 public A(B b) { this.b = b; } public void someMethod() { b.externalMethod(); } }
在Drools规则中,直接传入Mock的B实例:
// 构造Mock的B B mockB = Mockito.mock(B.class); // 设置externalMethod的行为,比如抛出指定异常或无操作 Mockito.doThrow(new YourCustomException()).when(mockB).externalMethod(); // 注入MockB创建A实例 A a = new A(mockB); a.someMethod(); // 触发Mock的预设行为,不会调用真实的externalMethod
这个方案完全规避静态Mock的限制,同时能自由设置Mock行为和断言异常,是最符合面向对象设计原则的解决方式。
2. 修正Mockito mockedConstruction的使用方式
如果无法重构A类,可调整mockedConstruction的使用逻辑,解决你遇到的两个问题:
解决多实例Mock限制
mockedConstruction支持同一线程内创建多个Mock实例,只需将所有A的创建逻辑放在同一个try-with-resources块中,所有new B()生成的实例都会被Mock:
try (MockedConstruction<B> mockedB = Mockito.mockConstruction(B.class)) { // 创建多个A实例,每个内部的B都是Mock对象 A a1 = new A("x1", "y1"); A a2 = new A("x2", "y2"); // 获取所有Mock的B实例,分别设置不同行为 List<B> mocks = mockedB.constructed(); Mockito.doThrow(new YourCustomException()).when(mocks.get(0)).externalMethod(); Mockito.doNothing().when(mocks.get(1)).externalMethod(); // 调用方法验证行为 assertThrows(YourCustomException.class, a1::someMethod); a2.someMethod(); // 无实际操作 }
解决异常断言时机问题
不要在Mock构造的Lambda内直接执行doThrow,而是在Lambda中为每个新创建的Mock预设行为,或者在实例创建后获取Mock对象设置行为,这样异常只会在调用externalMethod时触发:
try (MockedConstruction<B> mockedB = Mockito.mockConstruction(B.class, (mock, context) -> { // 为每个新创建的B Mock预设异常行为 Mockito.doThrow(new YourCustomException()).when(mock).externalMethod(); })) { A a = new A("x", "y"); // 此时调用someMethod才会抛出异常 assertThrows(YourCustomException.class, a::someMethod); }
3. 使用PowerMock扩展Mock能力(适用于无法重构且Mockito受限场景)
如果上述Mockito方式仍无法满足需求,可使用PowerMock来Mock B的构造函数,它支持更灵活的静态Mock逻辑,同一线程内可创建多个Mock实例:
先确保引入PowerMock依赖,再编写测试代码:
@RunWith(PowerMockRunner.class) @PrepareForTest(B.class) public class DroolsRuleTest { @Test public void testAWithMockB() { // Mock B的构造函数,返回指定Mock实例 B mockB = Mockito.mock(B.class); PowerMockito.whenNew(B.class).withAnyArguments().thenReturn(mockB); // 设置Mock行为 Mockito.doThrow(new YourCustomException()).when(mockB).externalMethod(); // 在Drools规则中创建A实例 A a = new A("x", "y"); assertThrows(YourCustomException.class, a::someMethod); } }
注意:PowerMock需要特定的运行器和类准备配置,需确保Drools的执行环境兼容PowerMock的类加载逻辑。
内容的提问来源于stack exchange,提问作者abhi gang
相关产品推荐
相关产品推荐

