sharon gur
sharon gur

Reputation: 383

Testing a private method in unit testing

I know the answer to this question is: you do not test private method but only the public method that will eventually lead to that private method invocation.

BUT In my case, the public method actually starting up a consumer/connection to kafka, so i only want to test the logic done when a kafka message is received. I do not want to make the logic method public as no one will use it out side of the kafka infrastructure, but still i want to unit test the logic done there.

What is the best practice solution? I can change the code if need be

Heres some examples:

the private method in question

 private void handleConsumerRecord(ConsumerRecord<PK, byte[]> cr, Acknowledgment acknowledgment) throws IOException {
//logic to be tested
}

the private method that calls the private logic method

/**
     * Initialize the kafka message listener
     */
    private void initConsumerMessageListenerContainer(ProducerFactory<PK, V> producerFactory) {
        if (!processAsBatch) {
            // start a acknowledge message listener to allow the manual commit
            acknowledgingMessageListener =  (cr, acknowledgment) -> {
                try {
                    handleConsumerRecord(cr, acknowledgment);
                } catch (IOException e) {
                    log.error("Failed to handle consumed message, commiting message and performing irrecoverableException actions");
                    exceptionHandlerManager.getIrrecoverableExceptionHandler().performAction(null, cr.value(), cr.topic(), cr.key());
                }
            };

            // start and initialize the consumer container
            container = initContainer(acknowledgingMessageListener, producerFactory);
}

and this is the public method that starts everything

/**
     * Start the message consumer
     * The record event will be delegate on the onMessage()
     */
    public void start(ProducerFactory<PK, V> producerFactory) {
        initConsumerMessageListenerContainer(producerFactory);
        container.start();
    }

The unit test i tried to write

    kafkaByteArrConsumer.getAcknowledgingMessageListener().onMessage(record, acknowledgment);
        doThrow(TemporaryException.class).when(kafkaByteArrConsumer).getConsumerMessageLogic().onMessage(record.value(), acknowledgment);
        Mockito.verify(exceptionHandlerManager.getTemporaryExceptionHandler(), Mockito.times(1))
                .performAction();

As you can see, the getAcknowledgingMessageListener will not be initialized by the initConsumerMessageListenerContainer() and therefore i wont be able to access the handleConsumer method when mocking .getConsumerMessageLogic().onMessage

(which is called by the //some logic to be tested part)

Upvotes: 0

Views: 355

Answers (2)

Michael Gantman
Michael Gantman

Reputation: 7808

A good compromise would be to change your method to protected or even to package-private, and then have your unit test located in the same package. The unit-test class doesn't have to reside under the same root. Say your source resides under "source" folder and tests reside under "test" folder. Just have the testing class reside in the same package. A very detailed answer could be found in this question: How can we test package-private class? . Your question may be a duplicate of that question

Upvotes: 1

Michal Drozd
Michal Drozd

Reputation: 1351

Well, there are people who use PowerMock to test private methods etc. but I always recommend to avoid that. Maybe you should consider change your logic a little there or even better consider Kafka MockConsumer etc.

Upvotes: 0

Related Questions