如何对kafka客户应用程序执行功能测试?

时间:2018-07-10 15:28:45

标签: scala testing apache-kafka kafka-consumer-api scalatest

我想测试一个使用Kafka消息并将其写入日志的应用程序。这是类似scala的伪代码的近似表示:

import kafka.consumer.Consumer
import kafka.consumer.ConsumerConfig
import org.slf4j.LoggerFactory
import java.util.Properties
import java.util.HashMap

object ConsumerApp extends App {
  val topic = new HashMap[String, Integer]()
  topic.put("test", 1)
  val logger = LoggerFactory.getLogger(getClass().getName())
  val messageStream = Consumer
    .createJavaConsumerConnector(new ConsumerConfig(new Properties()))
    .createMessageStreams(topic)
    .get(topic).get(0)
  for (message <- messageStream) {
    val gotMessage = new String(message.message())
    logger.info(gotMessage)
  }
}

我想到的测试场景如下:

  • Kafka服务器已启动。

  • 应用程序启动并连接到Kafka服务器,开始侦听特定于主题的消息。

  • 一条消息发送到该主题。

  • 应用程序使用该消息并对其进行记录。

这是类似scala的伪代码的测试草案:

import uk.org.lidalia.slf4jtest.TestLoggerFactory;
import uk.org.lidalia.slf4jtest.LoggingEvent.info;

abstract class UnitSpec extends FlatSpec with Matchers with EmbeddedKafka {

}

class ConsumerAppSpec extends UnitSpec {
  "ConsumerApp" should "consume and log messages from Kafka on specific topic" in {
    withRunningKafka {
      val consumer = ConsumerApp
      // interecept logger to be able to test that the kafka message is logged
      val logger = TestLoggerFactory.getTestLogger(consumer.getClass)
      // start the application, but beforehand do something to prevent it infinitely blocking
      ???
      consumer.main(Array())  

      // publish a test message    
      publishStringMessageToKafka("test", "TEST")
      // Confirm that the message has been properly logged
      ???
    }
    EmbeddedKafka.stop()
  }
}

我的问题是测试代码的头三个问号。如果我执行main()方法,它将不会终止,从而阻止了其余测试的执行。

1 个答案:

答案 0 :(得分:0)

使其发挥作用...

object ConsumerApp extends App {

   def doStuff() {
      val topic = ...
      // more stuff ...
   }

   doStuff()
 }

 class ConsumerAppSpec {
   // ...
   consumer.doStuff()
   // ...
   publishMessage() 
 }

更新

我想,我误解了这个问题。我应该说不要阻塞线程:)

,而不是“不要调用main”。
 class ConsumerAppSpec {
   ...
   val futureResult = Future(consumer.doStuff)
   ...
   publishMessage()
 }