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

如何在JUnit结合Mockito中访问被测类的私有字段

如何在JUnit+Mockito测试中访问被测类的私有List字段?

你现在的场景很典型:被测类里藏着个私有private List<Person> people字段,执行完方法后需要确认特定状态的Person对象是不是已经被放进这个列表里了。先说说你示例里的问题——你Mock了这个List,这其实会让你没法验证真实的对象状态,因为Mock的List只会记录调用行为,不会真的存储添加的对象。下面给你几个实用的解决方案:

方案1:用@Spy注入真实List(推荐)

把Mock换成真实的List,用@Spy注解让Mockito把它注入到被测类的私有字段里,这样被测类对List的所有操作都会作用在这个真实的列表上,测试时直接访问它就行:

@RunWith(MockitoJUnitRunner.class)
public class Testclass {
    @InjectMocks
    private TestedClass tested;

    // 用真实ArrayList,@Spy会把它注入被测类的people字段(名字不匹配就加name属性)
    @Spy(name = "people")
    private List<Person> people = new ArrayList<>();

    @Test
    public void testPersonAddedCorrectly() {
        // 执行被测方法
        tested.addPersonWithSpecificState();

        // 直接验证列表内容
        assertEquals(1, people.size());
        Person addedPerson = people.get(0);
        // 验证对象状态,比如是不是激活状态、名字是否正确
        assertTrue(addedPerson.isActive());
        assertEquals("Flamp", addedPerson.getLastName());
    }
}

这个方法既保留了封装性,又能方便验证真实的对象状态,是最推荐的方式。

方案2:用反射直接读取私有字段

如果不想用Spy,反射也是个直接的办法,虽然代码有点繁琐,但胜在不需要修改被测类或依赖Spy:

@Test
public void testPersonAddedWithReflection() throws NoSuchFieldException, IllegalAccessException {
    // 执行被测方法
    tested.addPersonWithSpecificState();

    // 反射获取私有字段,设置为可访问
    Field peopleField = TestedClass.class.getDeclaredField("people");
    peopleField.setAccessible(true);
    List<Person> people = (List<Person>) peopleField.get(tested);

    // 验证逻辑
    assertNotNull(people);
    assertEquals(1, people.size());
    Person targetPerson = people.get(0);
    assertEquals("Jack", targetPerson.getFirstName());
}

注意:如果被测类的字段名改了,这个测试会直接报错,维护性不如方案1,所以尽量少用。

方案3:给被测类加测试专用的访问方法(最符合封装)

如果可以修改被测类,优先考虑加一个包访问权限的getter方法(别随便改成public,破坏封装),这样测试时就能直接调用:

// 被测类里的方法(和测试类同包的话,不用加public)
List<Person> getPeople() {
    return people;
}

// 测试类里的验证逻辑
@Test
public void testPersonAddedWithGetter() {
    tested.addPersonWithSpecificState();
    List<Person> people = tested.getPeople();
    // 验证对象状态...
}

这个方法是最符合面向对象封装原则的,毕竟测试也应该尽量通过类的公开/包内接口来验证状态。

最后再提醒一句:你之前Mock List的思路不对,因为Mock的List不会真的存储对象,只能验证有没有调用add方法,但没法验证添加的对象是不是你期望的那个特定状态的实例,所以一定要换成真实的List来测试哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:54:57