You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 08:12:33