【问题标题】:How to Inject a service call into another method?如何将服务调用注入另一个方法?
【发布时间】:2020-10-26 17:27:32
【问题描述】:
如何在另一个方法中模拟外部调用?
我模拟了服务,但由于我没有传递模拟服务,因此该方法没有获得模拟服务。
有没有办法注入服务?
@EnableAutoConfiguration
public class MyKafkaClass(){
private final ISaveData saveData;
public void save(){
//trying to mock the below method
saveData.persistAddress(address);
}
}
public class MyKafkaTest(){
MyKafkaClass kafkaClass = mock(MyKafkaClass.class);
ISaveData saveData = mock(ISaveData.class);
@Test
public void saveTest(){
//Getting a null pointer exception at the below line. How do i inject ISaveData ?
doNothing().when(saveData.persistAddress(any());
kafkaClass.save();
}
}
【问题讨论】:
标签:
spring-boot
junit
mockito
【解决方案1】:
你不应该模拟 MyKafkaClass
试试
@InjectMocks
MyKafkaClass kafkaClass;
@Mock
ISaveData saveData;
【解决方案2】:
这段代码在很多方面都是错误的:
-
虽然问题与 spring 无关,但 @EnableAutoConfiguration 不应该放在常规 bean 上(例如 MyKafkaClass),因为你已经标记了 spring-boot,很可能你已经在使用 @SpringBootApplication 注释自动启用自动配置的主类(参见@SpringBootApplication 的源代码,它本身标有@EnableAutoConfiguration。
-
由于您使用的是 final 字段,因此您可能有构造函数注入:
public class MyKafkaClass {
private final ISaveData saveData;
public MyKafkaClass(ISaveData saveData) {
this.saveData = saveData;
}
public void save(){
//trying to mock the below method
saveData.persistAddress(address);
}
这很重要,因为您的测试在概念上也是错误的:如果您正在测试 MyKafkaClass,模拟这个类没有意义,相反,您应该创建它并测试它的代码,这就是测试的目的。 ..
所以你的测试应该是这样的:
public class MyKafkaTest(){
ISaveData saveData = mock(ISaveData.class);
@Test
public void saveTest(){
// setup:
// this is the 'object-under-test', not a mock!
MyKafkaClass kafkaClass = new MyKafkaClass(saveData); // constructor injection is done here !
// specify expectations for your stubs/mocks
doNothing().when(saveData.persistAddress(any());
// when: running the operation that you want to test
kafkaClass.save();
// then:
// here you should verify the outcome of the test
}
现在,Mockito 库确实提供了一些方便的东西,例如 @InjectMocks 和 @Mock(因为您应该使用特殊的 mockito 运行器 (junit4) 或扩展程序 (junit5) 运行测试,但这看起来很高级的东西在这一点上,我建议您首先了解正确单元测试背后的概念,而不管实际的工具...