Mockito:模拟私有字段初始化

时间:2016-03-23 09:14:16

标签: java mockito junit4 powermockito

如何模拟正在内联初始化的字段变量?

e.g。

class Test {
    private Person person = new Person();
    ...
    public void testMethod() {
        person.someMethod();
        ...
    }
}

我想在测试方法时模拟 person.someMethod() - 测试#testMethod。

我需要模拟person变量的初始化。任何线索?

编辑:我不允许修改Person类。

6 个答案:

答案 0 :(得分:73)

Mockito附带了一个助手类来为你节省一些反射锅炉板代码:

import org.mockito.internal.util.reflection.Whitebox;

//...

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    Whitebox.setInternalState(underTest, "person", mockedPerson);
    // ...
}

<强>更新 不幸的是,模拟团队决定在Mockito 2中remove the class。所以你回来编写自己的反射样板代码,使用另一个库(例如Apache Commons Lang),或者只是窃取Whitebox类(它是MIT licensed)。

更新2: JUnit 5附带了自己的ReflectionSupportAnnotationSupport类,这些类可能很有用,可以避免您拉入另一个库。

答案 1 :(得分:18)

我已经找到了这个问题的解决方案,我忘了在这里发布。

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Test.class })
public class SampleTest {

@Mock
Person person;

@Test
public void testPrintName() throws Exception {
    PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
    Test test= new Test();
    test.testMethod();
    }
}

此解决方案的关键点是:

  1. 使用PowerMockRunner运行我的测试用例:@RunWith(PowerMockRunner.class)

  2. 指示Powermock准备Test.class以操纵私人字段:@PrepareForTest({ Test.class })

  3. 最后模拟Person类的构造函数:

    PowerMockito.mockStatic(Person.class); PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);

答案 2 :(得分:12)

参加聚会的时间很晚,但是我被打中了,并得到了朋友的帮助。根本不使用PowerMock。这适用于最新版本的Mockito。

Mockito随附此org.mockito.internal.util.reflection.FieldSetter

它的主要作用是帮助您使用反射来修改私有字段。

这是您的用法-

@Mock
private Person mockedPerson;
private Test underTest;

// ...

@Test
public void testMethod() {
    FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person", mockedPerson);
    // ...
    verify(mockedPerson).someMethod()

}

这样,您可以传递一个模拟对象,然后在以后对其进行验证。

参考:

https://www.codota.com/code/java/methods/org.mockito.internal.util.reflection.FieldSetter/set

答案 3 :(得分:8)

如果您使用Spring Test,请尝试 org.springframework.test.util.ReflectionTestUtils

 ReflectionTestUtils.setField(testObject, "person", mockedPerson);

答案 4 :(得分:6)

以下代码可用于在REST客户端模拟中初始化映射器。 mapper字段是私有的,需要在单元测试设置期间进行设置。

import org.mockito.internal.util.reflection.FieldSetter;

new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());

答案 5 :(得分:3)

如果需要为所有测试将变量设置为相同的值,则可以使用@Jarda的指南进行定义:

@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
    FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}

但是请注意,将私有值设置为其他值时应格外小心。如果它们是私有的,则出于某种原因。

例如,我使用它来更改单元测试中的睡眠等待时间。在真实的示例中,我想睡觉10秒钟,但是在单元测试中,我很满意它是否立即生效。在集成测试中,您应该测试实际价值。