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

如何模拟继承方法调用?Mockito模拟失效问题求助

问题分析与解决方案

核心问题

模拟失效的根本原因是:待测试的collectData方法内部直接通过new DataB(dbCon)、new DataC(dbCon)创建实例,你在测试类中@Mock出来的dataB/dataC对象,和方法内新建的实例完全是两个独立对象,Mockito的模拟规则根本作用不到方法内的真实实例上,自然会执行真实的数据库逻辑触发异常。

解决方案

方案一:重构代码(推荐,符合依赖注入原则)

修改待测试方法,不在内部直接new对象,而是通过外部传入实例或注入工厂类,让测试时可以控制DataB/DataC的实例创建。

方式1:参数注入实例

重构后的待测试方法:

public TypeA collectData(Connection dbCon, String id, DataB dataB, DataC dataC){
   TypeA a = new TypeA();
   a.setTime(LocalDateTime.now());
   a.setId(id);
   
   TypeB b = dataB.getData(id);
   a.setB(b);

   List<TypeC> c = dataC.getDataList(id);
   a.getC().addAll(c);
   
   return a;
}

对应测试代码:

@ExtendWith(MockitoExtension.class)
class DataTest {
   @Mock private Connection c;
   @Mock private DataB dataB;
   @Mock private DataC dataC;

   @Test
   void testTypeA(){
      // 模拟方法返回值
      when(dataB.getData("123")).thenReturn(new TypeB());
      List<TypeC> cL = new ArrayList<>();
      cL.add(new TypeC());
      when(dataC.getDataList("123")).thenReturn(cL);

      // 传入Mock对象执行测试
      TypeA a = collectData(c, "123", dataB, dataC);
      assertThat(a.getId(), is(equalTo("123")));
      // 其他断言逻辑
   }
}

方式2:工厂模式封装实例创建

如果不想修改方法参数,可以用工厂类封装DataB/DataC的创建:

// 定义工厂接口
public interface DataFactory {
    DataB createDataB(Connection dbCon);
    DataC createDataC(Connection dbCon);
}

// 真实工厂实现
public class DefaultDataFactory implements DataFactory {
    @Override
    public DataB createDataB(Connection dbCon) {
        return new DataB(dbCon);
    }

    @Override
    public DataC createDataC(Connection dbCon) {
        return new DataC(dbCon);
    }
}

修改待测试方法(假设所在类注入了DataFactory):

private final DataFactory dataFactory;

// 构造注入工厂
public YourClass(DataFactory dataFactory) {
    this.dataFactory = dataFactory;
}

public TypeA collectData(Connection dbCon, String id){
   TypeA a = new TypeA();
   a.setTime(LocalDateTime.now());
   a.setId(id);
   
   DataB dataB = dataFactory.createDataB(dbCon);
   TypeB b = dataB.getData(id);
   a.setB(b);

   DataC dataC = dataFactory.createDataC(dbCon);
   List<TypeC> c = dataC.getDataList(id);
   a.getC().addAll(c);
   
   return a;
}

对应测试代码:

@ExtendWith(MockitoExtension.class)
class DataTest {
   @Mock private Connection c;
   @Mock private DataB dataB;
   @Mock private DataC dataC;
   @Mock private DataFactory dataFactory;

   @Test
   void testTypeA(){
      // 模拟工厂返回Mock实例
      when(dataFactory.createDataB(c)).thenReturn(dataB);
      when(dataFactory.createDataC(c)).thenReturn(dataC);
      
      // 模拟方法返回值
      when(dataB.getData("123")).thenReturn(new TypeB());
      List<TypeC> cL = new ArrayList<>();
      cL.add(new TypeC());
      when(dataC.getDataList("123")).thenReturn(cL);

      TypeA a = collectData(c, "123");
      assertThat(a.getId(), is(equalTo("123")));
   }
}

方案二:使用PowerMockito拦截new操作(不推荐,仅应急)

如果无法重构原有代码,可以用PowerMockito拦截方法内的new操作,强制返回Mock对象。

Maven依赖配置

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

测试代码

@RunWith(PowerMockRunner.class)
@PrepareForTest({YourCollectDataClass.class}) // 替换为collectData方法所在的类名
class DataTest {
    @Mock private Connection c;
    @Mock private DataB dataB;
    @Mock private DataC dataC;

    @Test
    void testTypeA() throws Exception {
        // 拦截new DataB(dbCon),返回Mock实例
        PowerMockito.whenNew(DataB.class).withArguments(c).thenReturn(dataB);
        // 拦截new DataC(dbCon),返回Mock实例
        PowerMockito.whenNew(DataC.class).withArguments(c).thenReturn(dataC);

        // 模拟方法返回值
        when(dataB.getData("123")).thenReturn(new TypeB());
        List<TypeC> cL = new ArrayList<>();
        cL.add(new TypeC());
        when(dataC.getDataList("123")).thenReturn(cL);

        TypeA a = collectData(c, "123");
        assertThat(a.getId(), is(equalTo("123")));
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:35:28