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

Spy被测对象(SUT)后如何设置声明字段?解决NoSuchFieldException异常

解决Mockito Spy后反射找不到字段的问题

问题原因

当使用Mockito.spy()创建被测对象(SUT)时,实际得到的是Mockito动态生成的代理子类,而非TestedClass本身。调用sut.getClass()返回的是代理类,而getDeclaredField()仅查找当前类声明的字段,不会遍历父类,因此无法找到TestedClass中定义的field1、field2,抛出NoSuchFieldException。

解决方案

方案1:直接从原类获取字段定义

修改反射设置字段的方法,直接基于TestedClass的Class对象获取字段,而非代理类:

private void setSutField(String fieldName, Object value) throws Exception {
    // 直接使用原被测类的Class,跳过代理类
    Field field = TestedClass.class.getDeclaredField(fieldName);
    field.setAccessible(true);
    field.set(sut, value);
}

这种方法绕开了代理类的限制,直接操作原类的字段定义,确保能找到目标字段。

方案2:正确使用@Spy + @Mock注解实现自动注入

之前的注解用法错误导致初始化失败,正确配置方式如下:

public class TestClass {
    // @Spy注解:Mockito自动创建TestedClass的Spy实例
    @Spy
    private TestedClass sut;

    // @Mock注解:自动创建Mock对象
    @Mock
    private SomeClass1 field1;
    @Mock
    private SomeClass2 field2;

    @BeforeMethod
    public void setup() {
        // 初始化所有Mockito注解
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void test1() {
        // Stub protected方法示例
        doReturn(mockResult).when(sut).yourProtectedMethod();
        // 直接使用sut,field1和field2已自动注入
    }
}

注意事项:

  • @Spy无需手动new实例,Mockito会自动创建;若需自定义实例,可写成@Spy private TestedClass sut = new TestedClass();
  • 必须调用MockitoAnnotations.openMocks(this)完成注解初始化(或使用MockitoJUnitRunner运行测试)
  • Mockito会自动按字段名匹配,将@Mock对象注入到@Spy实例的对应public字段中,无需额外配置

方案3:先注入字段再创建Spy

先给真实的TestedClass实例设置Mock字段,再基于该实例创建Spy:

@BeforeMethod
public void setup() {
    // 创建真实实例并注入Mock字段
    TestedClass realInstance = new TestedClass();
    realInstance.field1 = Mockito.mock(SomeClass1.class);
    realInstance.field2 = Mockito.mock(SomeClass2.class);
    // 基于已注入字段的实例创建Spy
    sut = Mockito.spy(realInstance);
    // Stub目标protected方法
    doReturn(mockValue).when(sut).yourProtectedMethod();
}

这种方式更直观,避免反射操作,同时确保Spy后的对象保留已设置的字段值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 16:27:38