Java Mockito 将模拟注入 Spy 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43926636/
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 Inject mock into Spy object
提问by Wildchild
I'm writing a test case for a Class which has a 2 level of dependency injection. I use @Spy annotation for the 1 level dependency injection object, and I would like to Mock the 2nd level of injection. However, I kept getting null pointer exception on the 2nd level. Is there any way that I inject the mock into the @Spy object?
我正在为一个具有 2 级依赖注入的类编写测试用例。我对 1 级依赖注入对象使用 @Spy 注释,我想模拟第二级注入。但是,我一直在第二级收到空指针异常。有什么方法可以将模拟注入@Spy 对象?
public class CarTestCase{
@Mock
private Configuration configuration;
@Spy
private Engine engine;
@InjectMocks
private Car car;
@Test
public void test(){
Mockito.when(configuration.getProperties("")).return("Something");
car.drive();
}
}
public class Car{
@Inject
private Engine engine;
public void drive(){
engine.start();
}
}
public class Engine{
@Inject
private Configuration configuration;
public void start(){
configuration.getProperties(); // null pointer exception
}
}
采纳答案by Sergii Bishyr
Mockito cannot perform such a tricky injections as it's not an injection framework. So, you need to refactor your code to make it more testable. It's easy done by using constructor injection:
Mockito 不能执行如此棘手的注入,因为它不是一个注入框架。因此,您需要重构代码以使其更具可测试性。使用构造函数注入很容易完成:
public class Engine{
private Configuration configuration;
@Inject
public Engine(Configuration configuration) {
this.configuration = configuration;
}
........
}
public class Car{
private Engine engine;
@Inject
public Car(Engine engine) {
this.engine = engine;
}
}
In this case you have to handle the mocking and injection manually:
在这种情况下,您必须手动处理模拟和注入:
public class CarTestCase{
private Configuration configuration;
private Engine engine;
private Car car;
@Before
public void setUp(){
configuration = mock(Configuration.class);
engine = spy(new Engine(configuration));
car = new Car(engine);
}
@Test
public void test(){
Mockito.when(configuration.getProperties("")).return("Something");
car.drive();
}
}
回答by Yoory N.
I've also wandered how to inject a mock into a spy.
我还徘徊如何将模拟注入间谍。
The following approach will notwork:
下面的方法将无法正常工作:
@Spy
@InjectMocks
private MySpy spy;
But the desired behavior can be achieved by a "hybrid" approach, when using both annotation and manual mocking. The following works perfectly:
但是,当同时使用注释和手动模拟时,可以通过“混合”方法来实现所需的行为。以下工作完美:
@Mock
private NeedToBeMocked needToBeMocked;
@InjectMocks
private MySpy mySpy;
@InjectMocks
private SubjectUnderTest sut;
@BeforeMethod
public void setUp() {
mySpy = Mockito.spy(new MySpy());
MockitoAnnotations.initMocks(this);
}
(SubjectUnderTest
here depends on MySpy
, and MySpy
in its turn depends on NeedToBeMocked
).
(SubjectUnderTest
这里取决于MySpy
,MySpy
反过来又取决于NeedToBeMocked
)。
UPD:Personally, I think that if you have to do such a magic too often, it might be a sign that there is something wrong with dependenicies between your classes and it is worth to perform a little bit of refactoring to improve your code.
UPD:就我个人而言,我认为如果你不得不经常做这样的魔术,这可能表明你的类之间的依赖关系有问题,值得进行一点重构以改进你的代码。
回答by Hyman Yang
I also met this issue during the unit testing with Spring boot framework, but I found one solution for using both @Spy and @InjectMocks
我在使用 Spring boot 框架进行单元测试时也遇到了这个问题,但我找到了一种同时使用 @Spy 和 @InjectMocks 的解决方案
Previous answer from Yoory N.
Yoory N 之前的回答
@Spy
@InjectMocks
private MySpy spy;
Because InjectMocks need to have instance created, so the solution works for me is at below,
因为 InjectMocks 需要创建实例,所以对我有用的解决方案如下,
@Spy
@InjectMocks
private MySpy spy = new MySpy();
回答by DavidBu
I think I just found the definitive answer. I tried Yoory approach but changed the order of the annotations :
我想我刚刚找到了明确的答案。我尝试了 Yoory 方法,但更改了注释的顺序:
@InjectMocks
@Spy
private MySpy spy;
I assume that Mockito first creates the mock, and adds a spy on top of that. So there is no need to instantiate the MySpy object.
我假设 Mockito 首先创建了模拟,然后在其上添加了一个间谍。所以不需要实例化 MySpy 对象。
回答by Ahmad Shahwan
The (simplest) solution that worked for me.
对我有用的(最简单的)解决方案。
@InjectMocks
private MySpy spy = Mockito.spy(new MySpy());
No need for MockitoAnnotations.initMocks(this)
in this case, as long as test class is annotated with @RunWith(MockitoJUnitRunner.class)
.
MockitoAnnotations.initMocks(this)
在这种情况下不需要,只要测试类用@RunWith(MockitoJUnitRunner.class)
.