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

如何Mock类内部未作为参数传入的方法?Java Mockito测试答疑

问题:Mock非依赖注入的OtherClass实例是否生效?

业务代码(MyClass)

import name.package.OtherClass;
import name.package.Context;
import name.package.Configuration.keys;

public class MyClass{
    public static void configure(Context context){
       Configuration config = new OtherClass().getConfiguration(keys);
       context.configure(config);
    }
}

测试类(MyClassTest)

import org.mockito.Mock;
import org.mockito.Mockito;

public class MyClassTest{
   @Mock
   private Context context  = Mockito.mock(Context.class);
   
   @Mock
   private OtherClass otherClass  = Mockito.mock(OtherClass.class);
   
   @Mock
   private Context configurationMock  = Mockito.mock(Configuration.class);

   @Test
   public void testConfigure(){
      Mockito.when(otherClass.getConfiguration(keys)).thenReturn(configurationMock);
      MyClass.configure(context);
      verify(context.configure(configurationMock), times(1))
   }
}

核心疑问:测试类中Mock的OtherClass实例,能否对MyClass里new OtherClass().getConfiguration()的调用生效?


解答

1. 直接结论

你的Mock完全不会生效,因为MyClass中是通过new OtherClass()硬编码创建实例,和测试类里Mock的otherClass是两个完全独立的对象,Mockito无法拦截这种直接new出来的对象调用。

2. 问题根源

Mockito的Mock逻辑仅对被注入、传递到目标类的实例生效,但你的业务代码里没有任何依赖注入逻辑——运行时会自己创建全新的OtherClass实例,和测试类里的Mock实例毫无关联,所以你设置的when(otherClass.getConfiguration(keys))不会对业务代码产生任何影响。

3. 修复方案

方案一:重构业务代码,依赖注入OtherClass

修改MyClass的configure方法,将OtherClass作为参数传入,让测试时可以直接传递Mock实例:

public class MyClass{
    public static void configure(Context context, OtherClass otherClass){
        Configuration config = otherClass.getConfiguration(keys);
        context.configure(config);
    }
}

对应的测试代码调整:

@Test
public void testConfigure(){
    Mockito.when(otherClass.getConfiguration(keys)).thenReturn(configurationMock);
    // 传入Mock的otherClass
    MyClass.configure(context, otherClass);
    // 修正verify的写法
    Mockito.verify(context, Mockito.times(1)).configure(configurationMock);
}

方案二:使用字节码增强工具拦截new操作

如果无法修改业务代码,可以用PowerMock或Mockito的inline mock maker来拦截new OtherClass()的操作,强制返回Mock实例:
以PowerMock为例,测试类调整如下:

import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(PowerMockRunner.class)
// 告诉PowerMock要拦截MyClass中的new操作
@PrepareForTest(MyClass.class)
public class MyClassTest{
   @Mock
   private Context context;
   
   @Mock
   private OtherClass otherClass;
   
   @Mock
   private Configuration configurationMock;

   @Test
   public void testConfigure(){
      // 拦截new OtherClass(),返回Mock实例
      PowerMockito.whenNew(OtherClass.class).withNoArguments().thenReturn(otherClass);
      Mockito.when(otherClass.getConfiguration(keys)).thenReturn(configurationMock);
      
      MyClass.configure(context);
      
      Mockito.verify(context, Mockito.times(1)).configure(configurationMock);
   }
}

注意:PowerMock会修改字节码,需注意与JDK、Mockito的版本兼容性;Mockito 3.4+的inline mock maker也支持类似功能,配置方式略有不同。

4. 测试代码的额外问题

  • @Mock注解和Mockito.mock()重复,二者选其一即可,同时需确保测试类被Mockito处理器接管(比如添加@RunWith(MockitoJUnitRunner.class)或使用MockitoExtension)。
  • verify写法错误,正确格式是Mockito.verify(被验证对象, 次数).方法(参数),你当前的写法会直接调用方法而非验证调用次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:01:15