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

Mockito:Mock类构造函数并调用真实方法的单元测试问题

解决类A单元测试时跳过构造函数中getB()调用的方案

首先纠正原代码里的一处编译错误:类A的构造函数中变量名应为小写的b,原代码写成了大写B,修正后如下:

public A() {
  b = getB();
}

针对你的需求——不执行构造函数内的getB()调用,同时测试doSomething()的真实逻辑,提供以下几种可行方案:

方案1:创建A的测试子类重写getB()

利用Java继承特性,创建A的匿名子类并重写getB()方法,直接返回mock的B实例,让构造函数调用getB()时跳过原逻辑:

@Test
class TestA {
  @Mock
  B b;

  private A a;

  @BeforeMethod
  public void beforeMethod() {
    MockitoAnnotations.openMocks(this);
    // 创建A的子类,重写getB()返回mock对象
    a = new A() {
      @Override
      B getB() {
        return b;
      }
    };
  }

  @Test
  public void testMethod() {
    // 预设mock方法的返回值
    doReturn("预期结果").when(b).doOtherThing();
    // 执行真实的doSomething()方法
    a.doSomething();
    // 验证mock方法被调用
    verify(b).doOtherThing();
  }
}

方案2:使用Mockito的CALLS_REAL_METHODS创建Mock并手动注入字段

通过创建A的Mock实例并指定调用真实方法,再通过反射将mock的B注入到A的b字段,完全绕过构造函数中的getB()调用:

import java.lang.reflect.Field;
import org.mockito.Mockito;

@Test
class TestA {
  @Mock
  B b;

  private A a;

  @BeforeMethod
  public void beforeMethod() throws NoSuchFieldException, IllegalAccessException {
    MockitoAnnotations.openMocks(this);
    // 创建A的Mock实例,指定调用真实方法
    a = Mockito.mock(A.class, Mockito.CALLS_REAL_METHODS);
    // 通过反射设置A的b字段为mock对象
    Field bField = A.class.getDeclaredField("b");
    bField.setAccessible(true);
    bField.set(a, b);
  }

  @Test
  public void testMethod() {
    doReturn("预期结果").when(b).doOtherThing();
    a.doSomething();
    verify(b).doOtherThing();
  }
}

方案3:结合@Spy与doReturn提前拦截getB()

使用@Spy时默认会调用真实构造函数,需要在构造实例前预设getB()的返回值,确保构造函数调用时使用mock对象:

@Test
class TestA {
  @Mock
  B b;

  private A a;

  @BeforeMethod
  public void beforeMethod() {
    MockitoAnnotations.openMocks(this);
    // 先创建Spy实例,预设getB()返回mock对象
    a = Mockito.spy(A.class);
    Mockito.doReturn(b).when(a).getB();
    // 重新初始化实例,确保构造函数调用getB()时用预设返回值
    a = new A();
  }

  @Test
  public void testMethod() {
    doReturn("预期结果").when(b).doOtherThing();
    a.doSomething();
    verify(b).doOtherThing();
  }
}

方案说明

  • 方案1最简单直观,无需依赖反射或特殊配置,适合大多数常规场景;
  • 方案2完全绕过原构造函数逻辑,适合getB()逻辑复杂或无法通过子类重写的场景;
  • 方案3保留A的真实方法实现,同时精准拦截指定方法调用,兼顾灵活性和真实性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 22:08:16