英文:
Testing a private method in unit testing
问题
我知道这个问题的答案是:你不测试私有方法,而只测试最终会导致调用该私有方法的公有方法。
但是,在我的情况下,公共方法实际上启动了一个与kafka的消费者/连接,因此我只想测试接收kafka消息时执行的逻辑。
我不想将逻辑方法公开,因为除了kafka基础设施之外没有人会使用它,但我仍然想对其中执行的逻辑进行单元测试。
最佳实践解决方案是什么?如果需要,我可以更改代码。
以下是一些示例:
有问题的私有方法
private void handleConsumerRecord(ConsumerRecord<PK, byte[]> cr, Acknowledgment acknowledgment) throws IOException {
//要测试的逻辑
}
调用私有逻辑方法的私有方法
/**
* 初始化kafka消息监听器
*/
private void initConsumerMessageListenerContainer(ProducerFactory<PK, V> producerFactory) {
if (!processAsBatch) {
// 启动确认消息监听器以允许手动提交
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());
}
};
// 启动和初始化消费者容器
container = initContainer(acknowledgingMessageListener, producerFactory);
}
}
这是启动一切的公共方法
/**
* 启动消息消费者
* 记录事件将委托给onMessage()
*/
public void start(ProducerFactory<PK, V> producerFactory) {
initConsumerMessageListenerContainer(producerFactory);
container.start();
}
我尝试编写的单元测试
kafkaByteArrConsumer.getAcknowledgingMessageListener().onMessage(record, acknowledgment);
doThrow(TemporaryException.class).when(kafkaByteArrConsumer).getConsumerMessageLogic().onMessage(record.value(), acknowledgment);
Mockito.verify(exceptionHandlerManager.getTemporaryExceptionHandler(), Mockito.times(1))
.performAction();
正如你所看到的,getAcknowledgingMessageListener
将不会由 initConsumerMessageListenerContainer()
初始化,因此我将无法在模拟 .getConsumerMessageLogic().onMessage
时访问 handleConsumer
方法(这是由 "//要测试的逻辑" 部分调用的方法)。
英文:
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)
答案1
得分: 1
一个很好的妥协方案是将您的方法更改为protected
,甚至是package-private
,然后将您的单元测试放在同一个包中。单元测试类不必位于相同的根目录下。假设您的源代码位于“source”文件夹下,而测试位于“test”文件夹下。只需将测试类放置在同一个包中。关于这个问题可以在这个问题中找到非常详细的答案:我们如何测试package-private
类?。您的问题可能是该问题的重复。
英文:
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
答案2
得分: 0
好的,以下是您要翻译的内容:
嗯,有些人使用PowerMock来测试私有方法等,但我始终建议避免那样做。也许您应该考虑稍微更改您的逻辑,甚至更好地考虑使用Kafka的MockConsumer等。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论