0

I am trying to mock a org.apache.kafka.clients.producer.KafkaProducer. But the mock fails because of the implementation of the class. The input parameter is validated, if it is null a null pointer exception is thrown. How can I mock it?

The reason I think it fails is, The first parameter of the class KafkaProducer is a ProducerConfig which extends AbstractConfig. It validates the properties that is passed. If it is null, it throws a null pointer exception.

import org.apache.kafka.clients.producer.{KafkaProducer, ProducerConfig}
import org.scalamock.scalatest.MockFactory

object MyProducerTest extends MockFactory  with App {

  val mockKafkaProducer = mock[KafkaProducer[String,String]]

}

Exception in thread "main" java.lang.NullPointerException
    at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:52)
    at org.apache.kafka.common.config.AbstractConfig.<init>(AbstractConfig.java:63)
    at org.apache.kafka.clients.producer.ProducerConfig.<init>(ProducerConfig.java:340)
    at org.apache.kafka.clients.producer.KafkaProducer.<init>(KafkaProducer.java:166)
    at org.hs.My.tools.connector.MyProducerTest$$anon$1.<init>(MyProducerTest.scala:21)
    at org.hs.My.tools.connector.MyProducerTest$.delayedEndpoint$org$hs$My$tools$connector$MyProducerTest$1(MyProducerTest.scala:21)
    at org.hs.My.tools.connector.MyProducerTest$delayedInit$body.apply(MyProducerTest.scala:16)
    at scala.Function0.apply$mcV$sp(Function0.scala:39)
    at scala.Function0.apply$mcV$sp$(Function0.scala:39)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
    at scala.App.$anonfun$main$1$adapted(App.scala:80)
    at scala.collection.immutable.List.foreach(List.scala:392)
    at scala.App.main(App.scala:80)
    at scala.App.main$(App.scala:78)
    at org.hs.My.tools.connector.MyProducerTest$.main(MyProducerTest.scala:16)
    at org.hs.My.tools.connector.MyProducerTest.main(MyProducerTest.scala)

H Sridhar
  • 71
  • 7

1 Answers1

0

I think you can try extending the object with your own custom class.

class MyKafkaProducer extends KafkaProducer[String, String]()
val mockKafkaProducer = mock[MyKafkaProducer]

Or, mock the class above your KafkaProducer that makes the calls instead. Something like this:

# main:
class BusinessApp {

  // create a KafkaProducer

  def sendMessage(msg: String) = {
    kafkaProducer.send(new ProducerRecord(msg))
  }
}

# tests:
val mockBusinessApp = mock[BusinessApp]
(mockBusinessApp.sendMessage _).expects("test").returns(true)

Then you're not mocking the lower-level API of a KafkaProducer.

As a note, You could use embedded kafka and you don't have to mock KafkaProducer at all, and get actual messages produced/consumed during tests.

amdelamar
  • 346
  • 3
  • 16