Java 使用throw发送KafkaTemplate.send的Mockito抛出异常

Java 使用throw发送KafkaTemplate.send的Mockito抛出异常,java,spring-boot,junit,mockito,Java,Spring Boot,Junit,Mockito,我正在测试以下函数 公共布尔produceNumberOfPeople(NumberOfPeopleInPlacedToNumberOfPeopleInPlacedTo){ 最终生产记录=新生产记录( 卡夫卡诺图。按地点、主题划分的人数, numberOfPeopleInPlaceDTO.getId(), numberOfPeopleInPlaceDTO.getNumberOfPeople()); 试一试{ kafkaTemplate.send(record).get(2,TimeUnit.SE

我正在测试以下函数

公共布尔produceNumberOfPeople(NumberOfPeopleInPlacedToNumberOfPeopleInPlacedTo){
最终生产记录=新生产记录(
卡夫卡诺图。按地点、主题划分的人数,
numberOfPeopleInPlaceDTO.getId(),
numberOfPeopleInPlaceDTO.getNumberOfPeople());
试一试{
kafkaTemplate.send(record).get(2,TimeUnit.SECONDS);
返回true;
}
捕获(ExecutionException | TimeoutException | InterruptedException e){
返回false;
}
}
下面是测试代码

@测试
public void produceNumberOfPeopleTest()引发InterruptedException、ExecutionException、TimeoutException{
NumberOfPeopleInPlaceDTO NumberOfPeopleInPlaceDTO=NumberOfPeopleInPlaceDTO.builder()
.id(1)
.人数(10)
.build();
Mockito.when(kafkaTemplate.send(Mockito.any(ProducerRecord.class)))
.然后返回(可列出的未来);
Mockito.when(listenableFuture.get(2,TimeUnit.SECONDS))
.thenthow(TimeoutException.class);
Assert.assertFalse(placeService.produceNumberOfPeople(numberOfPeopleInPlaceDTO));
}
我定义了以下变量

@Autowired
私募服务;
@蚕豆
私人配售储存库;
@蚕豆
私人卡夫卡模板卡夫卡模板;
@蚕豆
私人可上市未来可上市未来;
问题是
kafkaTemplate.send(record).get(2,TimeUnit.SECONDS)
不会引发异常。所以测试总是失败


请告知我缺少的任何内容。

我建议创建失败的
ListenableFuture
对象,而不是
Mock

SettableListenableFuture<SendResult<String, Object>> future = new SettableListenableFuture<>();
future.setException(new RuntimeException())
因此,当调用该方法时,它抛出
ExecutionException

如果已通过set(Object)设置该值,则该方法返回该值;如果已通过setException(Throwable)设置异常,则抛出ExecutionException;如果已取消未来,则抛出CancellationException


问题是
PlaceService
没有使用
KafkaTemplate
的模拟实例。因此,我手动将mock实例传递给
PlaceService
的构造函数。现在测试通过了。
下面是新的测试代码

@测试
public void produceNumberOfPeopleTest()引发InterruptedException、ExecutionException、TimeoutException{
NumberOfPeopleInPlaceDTO NumberOfPeopleInPlaceDTO=NumberOfPeopleInPlaceDTO.builder()
.id(1)
.人数(10)
.build();
PlaceService testPlaceService=new-PlaceServiceImpl(null,kafkaTemplate);
SettableListenableFuture=新的SettableListenableFuture();
setException(新的RuntimeException());
Mockito.when(kafkaTemplate.send(Mockito.any(ProducerRecord.class)),然后return(future);
Assert.assertFalse(testPlaceService.produceNumberOfPeople(numberOfPeopleInPlaceDTO));
}

我很高兴您通过将实例传递给构造函数来解决问题。

然而,我将使用另一种方法,而不是创建适当的构造函数,并在测试方法本身中实例化
placeService
作为最佳实践,建议使用特定的setXXX方法来传递实例,例如在您的案例中,在PlaceService类中,您应该有如下内容:

public void setListenableFuture(ListenableFuture listenableFuture) {
   this.listenableFuture = listenableFuture;
}

public void setKafkaTemplate(KafkaTemplate<Integer, Integer> kafkaTemplate) {
   this.kafkaTemplate = kafkaTemplate;
}
通过这种方式,您可以将Mock对象和
placeService
保留为测试类的成员,这样JUnit和Spring Runner就有责任实例化这些对象并将它们注入
placeService
,然后您就可以定制将要编写的每个测试方法的Mock行为,根据您的需要。


根据我的经验,我发现这很有帮助,因为涉及的每个对象都有其适当的工作。即使在测试实现和可维护性方面,您也不必在每个测试方法中重复相同的代码。例如,考虑一下如果在某一点上您必须更改该构造函数会发生什么情况,在这种情况下,您也必须更改使用它的所有方法。你不觉得吗?

你是否确保“placeService”使用了正确的“listenableFuture”和“kafkaTemplate”模拟实例?你把那些例子传给它了吗?否则,您正在模拟的方法实际上永远不会产生预期的结果,因为调用是在不同的实例上进行的。@Marctizano您的建议帮助很大。谢谢
public void setListenableFuture(ListenableFuture listenableFuture) {
   this.listenableFuture = listenableFuture;
}

public void setKafkaTemplate(KafkaTemplate<Integer, Integer> kafkaTemplate) {
   this.kafkaTemplate = kafkaTemplate;
}
@Before
public void setUp() throws Exception {
   placeService.setListenableFuture(listenableFuture);
   placeService.setKafkaTemplate(kafkaTemplate);
}