如何在 Junit5 的函数中正确测试 kafkaTemplate.send()?

How to properly test kafkaTemplate.send() within a function in Junit5?

我正在学习如何编写测试,尤其是其中包含生产者的测试。我不能 post 所有 classes 因为它太大了(而且不是我的,我应该通过更改测试以使用 KafkaTemplate 来练习)。我不知道应该如何测试这样的调用。

由于我正在测试的函数中的 producer.send("topic", JsonObject),我遇到了 NPE。函数是这样构建的:

@Autowired
private KafkaTemplate<String,EventDto> kafkaTemplate;

public EventDto sendEvent(Event event) {
       EventDto eventToSend = this.dtoMapper.mapToDto(event, SomeEvent.class);
       this.kafkaTemplate.send("topic",eventToSend);
       return eventToSend;
   }

在单元测试中是这样的(省略无关部分):

@Test
void testSendEvent() {
      //omitted lines regarding second assert that works
      
      EventProducer producer = new EventProducer(something);
      EventDto dto = producer.sendEvent(Event.newBuilder().build());
      assertThat(dto).isNotNull();
      //there is a second assert here that passes, nothing to do with kafka
}

我们有 Mockito,我想我需要以某种方式模拟 KafkaTemplate。但是我不太明白如何“指导”sendEvent 在 producer.sendEvent() 调用中使用 KafkaTemplate?

解决方案编辑:我将 @Autowired 更改为使用构造函数注入它。效果很好!这是完整的 class 和现在的方法

@Service
public class EventProducer implements EventProducerInterface {

   private final DtoMapper dtoMapper;
   private KafkaTemplate<String,EventDto> kafkaTemplate;

   @Autowired
   public EventProducer (KafkaTemplate<String,EventDto> kafkaTemplate, IDtoMapper dtoMapper) {
          Assert.notNull(dtoMapper, "dtoMapper must not be null");
          this.dtoMapper = dtoMapper;
          this.kafkaTemplate=kafkaTemplate;
       }

   public EventDto sendEvent(Event event) {
       EventDto eventToSend = this.dtoMapper.mapToDto(event, EventDto.class);
       this.kafkaTemplate.send("output-topic",eventToSend);
       return eventToSend;
   }
}

你应该使用构造函数注入而不是 @Autowired:


private KafkaTemplate<String,EventDto> kafkaTemplate;

public EventProducer(KafkaTemplate<String,EventDto> kafkaTemplate, something) {
    this.kafkaTemplate = kafkaTemplate;
}

public EventDto sendEvent(Event event) {
       EventDto eventToSend = this.dtoMapper.mapToDto(event, SomeEvent.class);
       this.kafkaTemplate.send("topic",eventToSend);
       return eventToSend;
}

这样你就可以在你的测试中注入模拟:

@Test
void testSendEvent() {
      //omitted lines regarding second assert that works
      KafkaTemplate<<String,EventDto>> templateMock = mock(KafkaTemplate.class);
      EventProducer producer = new EventProducer(templateMock, something);
      EventDto dto = producer.sendEvent(Event.newBuilder().build());
      assertThat(dto).isNotNull();
      //there is a second assert here that passes, nothing to do with kafka
}

如果您不能更改 class' 构造函数,您可以使用 @MockBean:

提供一个模拟
@MockBean
KafkaTemplate<String,EventDto> kafkaTemplate;

@Test
void testSendEvent() {
      //omitted lines regarding second assert that works
      
      EventProducer producer = new EventProducer(something);
      EventDto dto = producer.sendEvent(Event.newBuilder().build());
      assertThat(dto).isNotNull();
      //there is a second assert here that passes, nothing to do with kafka
}

但是这个设计有些奇怪 - EventProducer class 有 @Autowired 和构造函数参数吗?自动装配仅适用于 bean,通常 class 具有默认构造函数和 @Autowired 依赖项,或者通过构造函数注入所有内容。

如果我提供的这些选项不适合您,请添加有关 class 构造函数和整体设计的更多详细信息。