我为一个具有2级依赖注入的类编写测试用例。我使用@Spy注释作为1级依赖注入对象,我想模拟第二级注入。但是,我一直在第二级获得空指针异常。有没有办法将模拟注入@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
}
}
答案 0 :(得分:16)
我也徘徊如何将模拟注入间谍。
以下方法将不工作:
@Spy
@InjectMocks
private MySpy spy;
但是,所期望的行为可以通过" hybrid"来实现。方法,当使用注释和手动模拟时。以下工作完美:
@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
此处取决于MySpy
,MySpy
依赖于NeedToBeMocked
)。
UPD:就个人而言,我认为如果你不得不经常做这样的魔术,这可能表明你的课程之间的依赖关系有问题,并且值得执行一个一点点重构,以改善您的代码。
答案 1 :(得分:11)
最适合我的解决方案。
@InjectMocks
private MySpy spy = Mockito.spy(new MySpy());
在这种情况下,只要测试类用MockitoAnnotations.initMocks(this)
注释,就不需要@RunWith(MockitoJUnitRunner.class)
。
答案 2 :(得分:9)
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;
}
}
在这种情况下,您必须手动处理模拟和注入:
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();
}
}
答案 3 :(得分:6)
在使用Spring Boot框架进行单元测试期间,我也遇到了这个问题,但是我找到了同时使用@Spy和@InjectMocks的一种解决方案
Yorory N的先前答案。
@Spy
@InjectMocks
private MySpy spy;
因为需要创建InjectMocks实例,所以下面的解决方案对我有用
@Spy
@InjectMocks
private MySpy spy = new MySpy();
答案 4 :(得分:1)
我想我刚刚找到了明确的答案。我尝试了Yoory方法,但更改了注释的顺序:
@InjectMocks
@Spy
private MySpy spy;
我假设Mockito首先创建了模拟,然后在其上添加了一个间谍。因此,无需实例化MySpy对象。