Java Mockito:模拟私有字段初始化
如何模拟正在内联初始化的字段变量Java Mockito:模拟私有字段初始化,java,mockito,junit4,powermockito,Java,Mockito,Junit4,Powermockito,如何模拟正在内联初始化的字段变量 class Test { private Person person = new Person(); ... public void testMethod() { person.someMethod(); ... } } 在这里,我想在测试Test.testMethod()方法时模拟person.someMethod(),我需要模拟person变量的初始化。有线索吗 编辑:我不允许修改Person
class Test {
private Person person = new Person();
...
public void testMethod() {
person.someMethod();
...
}
}
在这里,我想在测试Test.testMethod()
方法时模拟person.someMethod()
,我需要模拟person
变量的初始化。有线索吗
编辑:我不允许修改Person类。Mockito附带了一个helper类,可以为您保存一些代码:
import org.mockito.internal.util.reflection.Whitebox;
//...
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
Whitebox.setInternalState(underTest, "person", mockedPerson);
// ...
}
更新:
不幸的是,mockito团队决定加入mockito 2。因此,您可以重新编写自己的反射样板代码,使用另一个库(例如),或者简单地窃取类(它是)
更新2:
JUnit 5自带了自己的类和类,这些类可能很有用,可以帮助您避免使用另一个库。我已经找到了这个问题的解决方案,但我忘了在这里发布
@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();
}
}
此解决方案的关键点是:
@RunWith(PowerMockRunner.class)
Test.class
:@PrepareForTest({Test.class})
PowerMockito.mockStatic(Person.class)代码>
PowerMockito.whenNew(Person.class).withNoArguments()。然后返回(Person)代码>
参加聚会已经很晚了,但我在这里被打动了,并得到了一位朋友的帮助。问题是不要使用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();
}
通过这种方式,您可以传递模拟对象,然后稍后对其进行验证
是参考。以下代码可用于在REST客户端模拟中初始化映射程序。
mapper
字段是私有的,需要在单元测试设置期间进行设置
import org.mockito.internal.util.reflection.FieldSetter;
new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());
如果需要为所有测试设置相同的变量值,可以使用@Jarda的指南定义该变量:
@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}
但要注意的是,设置不同的私人价值观应该谨慎处理。如果他们是私人的,出于某种原因
例如,我使用它来更改单元测试中睡眠的等待时间。在真实的例子中,我想睡10秒钟,但在单元测试中,如果是立即的,我会感到满意。在集成测试中,您应该测试实际值。如果使用Spring测试,请尝试org.springframework.test.util.ReflectionTestUtils
此链接可能对您有所帮助。您应该重构代码,以便为
人员
传递模拟。选项包括添加构造函数来执行此操作,或添加setter方法。我正在监视我的目标对象是因为其他原因,在这种情况下,当我的对象是spy时,我无法以这种方式设置内部状态。为什么不呢?我用它来对付间谍。创建一个Person实例。存根任何需要存根的内容,然后在您的测试实例上设置它。警告:Whitebox位于内部
包中,在Mockito 2.6.2上似乎不再工作。您可以使用FieldSetter.setField()。我在下面给出了一个同样的例子。@Ralf,因为在Java中更改引用名称总是会导致编译错误。FieldSetter
在Mockito 2.x中不再可用。@Ralf我使用的是版本Mockito-core-2.15.0。在那里可以买到。不过仍然是beta。@RajKumar类#getDeclaredField
接受单个参数,因此paren需要看起来像FieldSetter.setField(underTest,underTest.getClass().getDeclaredField(“person”),mockedPerson)代码>。这就是为什么我把它弄错了,并认为在您的示例中修复它可能是一个好主意。谢谢回复。使用内部API不是最好的idea@RajKumar不错,但正如ZimboRodger提到的:使用内部API是个好主意吗?为什么是内针?它对测试非常有用。您的解释谈到了mockStatic
函数,但在您的代码示例中没有说明这一点。代码示例应该有mockStatic
调用,还是构造函数不需要这个调用?太好了!!!非常感谢你!伟大的可能有助于链接到本文,并可能包含需要的依赖项:build.gradle.kts:testImplementation(“org.springframework:spring test:5.1.2.RELEASE”)
Cool,这对我帮助很大,谢谢!这对JUnit5或spring:2.4.2不有用version@SolankiVaibhav为什么不呢?
ReflectionTestUtils.setField(testObject, "person", mockedPerson);