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

如何Mock方法内部初始化的对象?求技术实现建议

这确实是个挺常见的测试难题——当对象是在方法内部直接new出来的时候,常规的Mockito确实没法直接mock它。我给你几个实用的解决思路,从代码优化到工具绕过的都有:

解决方案一:重构代码(推荐,更符合设计原则)

把内部创建对象的逻辑抽成一个独立的方法,然后用Mockito的Spy来mock这个方法,让它返回我们预先准备好的mock对象。

首先修改你的业务类,把new SampleClass()的逻辑抽成一个protected方法:

public class YourClass {
    void myMethod(){ 
        SampleClass sample = createSampleClass(); 
        int count = sample.getProductCount(5L); 
    }

    // 抽出来的对象创建方法
    protected SampleClass createSampleClass() {
        return new SampleClass();
    }
}

然后在测试类里,用Spy来接管这个创建方法:

@Test
public void testMyMethod() {
    // 创建被测试类的Spy实例(保留原类的大部分逻辑,只mock指定方法)
    YourClass yourClassSpy = Mockito.spy(new YourClass());
    
    // 创建SampleClass的mock对象,并定义预期行为
    SampleClass mockSample = Mockito.mock(SampleClass.class);
    Mockito.when(mockSample.getProductCount(Mockito.any(Long.class))).thenReturn(10);
    
    // 让Spy的createSampleClass方法返回我们的mock对象
    Mockito.doReturn(mockSample).when(yourClassSpy).createSampleClass();
    
    // 执行测试方法
    yourClassSpy.myMethod();
    
    // 验证mock方法是否被正确调用
    Mockito.verify(mockSample).getProductCount(5L);
}

这个方案的好处是代码更具可测试性,也符合开闭原则,后续扩展SampleClass的创建逻辑也更方便。

解决方案二:用PowerMock直接mock构造方法(无需修改原代码)

如果因为各种原因没法修改业务代码,PowerMock可以帮你拦截构造方法的调用,直接返回mock对象。

首先要确保项目中引入了PowerMock和Mockito的组合依赖,然后测试类需要添加特定注解:

@RunWith(PowerMockRunner.class)
@PrepareForTest(YourClass.class) // 告诉PowerMock需要处理YourClass里的构造方法
public class YourClassTest {
    @Test
    public void testMyMethod() {
        // 创建SampleClass的mock对象并定义行为
        SampleClass mockSample = Mockito.mock(SampleClass.class);
        Mockito.when(mockSample.getProductCount(Mockito.any(Long.class))).thenReturn(10);
        
        // 拦截SampleClass的无参构造方法,返回我们的mock对象
        PowerMockito.whenNew(SampleClass.class).withNoArguments().thenReturn(mockSample);
        
        // 正常创建业务类实例并执行方法
        YourClass yourClass = new YourClass();
        yourClass.myMethod();
        
        // 验证调用逻辑
        Mockito.verify(mockSample).getProductCount(5L);
    }
}

注意:PowerMock是通过修改字节码实现的,部分项目如果有严格的字节码检查可能会有兼容性问题,所以这个方案是“无法修改代码”时的备选方案。

解决方案三:依赖注入替换内部创建(最佳实践)

如果SampleClass是一个业务服务类,最推荐的方式是把它作为依赖注入到你的业务类中,而不是在方法内部直接创建。

修改业务类,通过构造方法注入SampleClass:

public class YourClass {
    private final SampleClass sampleClass;
    
    // 构造方法注入依赖
    public YourClass(SampleClass sampleClass) {
        this.sampleClass = sampleClass;
    }

    void myMethod(){ 
        int count = sampleClass.getProductCount(5L); 
    }
}

测试时直接传入mock对象即可,完全不需要额外的工具:

@Test
public void testMyMethod() {
    SampleClass mockSample = Mockito.mock(SampleClass.class);
    Mockito.when(mockSample.getProductCount(5L)).thenReturn(10);
    
    // 直接把mock对象传入业务类
    YourClass yourClass = new YourClass(mockSample);
    yourClass.myMethod();
    
    // 验证调用
    Mockito.verify(mockSample).getProductCount(5L);
}

这个方案让类的依赖关系更加清晰,完全符合面向对象的依赖倒置原则,也是长期维护代码的最佳实践。


内容的提问来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:00:11