Java Mockito:模拟私有字段初始化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36173947/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mockito: Mock private field initialization
提问by Arun
How I can mock a field variable which is being initialized inline?
如何模拟正在内联初始化的字段变量?
e.g.
例如
class Test {
private Person person = new Person();
...
public void testMethod() {
person.someMethod();
...
}
}
Here I want to mock person.someMethod()while testing method - Test#testMethod.
在这里,我想在测试方法时模拟person.someMethod()- Test#testMethod。
for which I need to mock initialization of person variable. Any clue?
为此,我需要模拟 person 变量的初始化。有什么线索吗?
EDIT: I'm not allowed to modify Person class.
编辑:我不允许修改 Person 类。
采纳答案by Arun
I already found the solution to this problem which I forgot to post here.
我已经找到了这个问题的解决方案,我忘记在这里发布了。
@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();
}
}
Key points to this solution are:
该解决方案的关键点是:
Running my test cases with PowerMockRunner:
@RunWith(PowerMockRunner.class)
Instruct Powermock to prepare
Test.class
for manipulation of private fields:@PrepareForTest({ Test.class })
And finally mock the constructor for Person class:
PowerMockito.mockStatic(Person.class);
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
使用 PowerMockRunner 运行我的测试用例:
@RunWith(PowerMockRunner.class)
指示 Powermock 准备
Test.class
操作私有字段:@PrepareForTest({ Test.class })
最后模拟 Person 类的构造函数:
PowerMockito.mockStatic(Person.class);
PowerMockito.whenNew(Person.class).withNoArguments().thenReturn(person);
回答by Ralf
Mockito comes with a helper class to save you some reflection boiler plate code:
Mockito 带有一个辅助类来为您节省一些反射样板代码:
import org.mockito.internal.util.reflection.Whitebox;
//...
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
Whitebox.setInternalState(underTest, "person", mockedPerson);
// ...
}
Update:Unfortunately the mockito team decided to remove the classin Mockito 2. So you are back to writing your own reflection boilerplate code, use another library (e.g. Apache Commons Lang), or simply pilfer the Whiteboxclass (it is MIT licensed).
更新:不幸的是,mockito 团队决定在 Mockito 2 中删除该类。因此,您将重新编写自己的反射样板代码,使用另一个库(例如Apache Commons Lang),或者只是窃取Whitebox类(它是MIT 许可的)。
Update 2:JUnit 5 comes with its own ReflectionSupportand AnnotationSupportclasses that might be useful and save you from pulling in yet another library.
更新 2:JUnit 5 带有它自己的ReflectionSupport和AnnotationSupport类,这些类可能很有用,并使您免于引入另一个库。
回答by Raj Kumar
Pretty late to the party, but I was struck here and got help from a friend. The thing was not to use PowerMock. This works with the latest version of Mockito.
派对很晚了,但我在这里受到了打击,并得到了朋友的帮助。问题是不要使用 PowerMock。这适用于最新版本的 Mockito。
Mockito comes with this org.mockito.internal.util.reflection.FieldSetter
.
Mockito 带有这个org.mockito.internal.util.reflection.FieldSetter
。
What it basically does is helps you modify private fields using reflection.
它的主要作用是帮助您使用反射修改私有字段。
This is how you use it -
这就是你如何使用它 -
@Mock
private Person mockedPerson;
private Test underTest;
// ...
@Test
public void testMethod() {
FieldSetter.setField(underTest, underTest.getClass().getDeclaredField("person"), mockedPerson);
// ...
verify(mockedPerson).someMethod();
}
This way you can pass a mock object and then verify it later.
通过这种方式,您可以传递一个模拟对象,然后稍后对其进行验证。
Reference:
参考:
https://www.codota.com/code/java/methods/org.mockito.internal.util.reflection.FieldSetter/set
https://www.codota.com/code/java/methods/org.mockito.internal.util.reflection.FieldSetter/set
回答by Jarda Pavlí?ek
Following code can be used to initialize mapper in REST client mock. The mapper
field is private and needs to be set during unit test setup.
以下代码可用于在 REST 客户端模拟中初始化映射器。该mapper
字段是私有的,需要在单元测试设置期间设置。
import org.mockito.internal.util.reflection.FieldSetter;
new FieldSetter(client, Client.class.getDeclaredField("mapper")).set(new Mapper());
回答by Hugo Dias
Using @Jarda's guide you can define this if you need to set the variable the same value for all tests:
如果您需要为所有测试设置相同的变量值,则可以使用@Jarda 的指南来定义它:
@Before
public void setClientMapper() throws NoSuchFieldException, SecurityException{
FieldSetter.setField(client, client.getClass().getDeclaredField("mapper"), new Mapper());
}
But beware that setting private values to be different should be handled with care. If they are private are for some reason.
但请注意,应谨慎处理将私有值设置为不同的情况。如果它们是私人的,则是出于某种原因。
Example, I use it, for example, to change the wait time of a sleep in the unit tests. In real examples I want to sleep for 10 seconds but in unit-test I'm satisfied if it's immediate. In integration tests you should test the real value.
例如,我使用它来更改单元测试中睡眠的等待时间。在真实的例子中,我想睡 10 秒,但在单元测试中,如果它是即时的,我就很满意。在集成测试中,您应该测试真正的价值。
回答by Zimbo Rodger
In case you use Spring Test try org.springframework.test.util.ReflectionTestUtils
如果您使用 Spring Test,请尝试org.springframework.test.util.ReflectionTestUtils
ReflectionTestUtils.setField(testObject, "person", mockedPerson);