【问题标题】:Testing a private method in unit testing在单元测试中测试私有方法
【发布时间】:2020-09-30 10:23:13
【问题描述】:

我知道这个问题的答案是:您不测试私有方法,而只测试最终会导致该私有方法调用的公共方法。

但是 在我的例子中,公共方法实际上启动了一个消费者/连接到 kafka,所以我只想测试收到 kafka 消息时完成的逻辑。 我不想公开逻辑方法,因为没有人会在 kafka 基础架构之外使用它,但我仍然想对那里完成的逻辑进行单元测试。

最佳实践解决方案是什么?如果需要,我可以更改代码

这里有一些例子:

有问题的私有方法

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

调用私有逻辑方法的私有方法

/**
     * 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);
}

这是启动一切的公共方法

/**
     * Start the message consumer
     * The record event will be delegate on the 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 方法

(由//一些待测逻辑部分调用)

【问题讨论】:

  • 我认为一些单元测试框架可以测试私有方法。反射和宽容的安全管理器将允许这样做。 OTOH 我经常制作一个私有方法包私有,以便可以使用测试工具直接调用它(它本身在同一个包中)。我添加了一条注释,在这些情况下,方法是包私有的“仅用于测试”。
  • 是的,我知道 PowerMock 可以测试私有方法...但我想要最佳实践解决方案,我似乎无法考虑可以解决它的设计更改,我确定有一个。

标签: java junit


【解决方案1】:

一个很好的折衷方案是将您的方法更改为受保护甚至是包私有,然后将您的单元测试放在同一个包中。单元测试类不必驻留在同一根目录下。假设您的源位于“source”文件夹下,而测试位于“test”文件夹下。只需让测试类驻留在同一个包中。在这个问题中可以找到非常详细的答案:How can we test package-private class? 。您的问题可能与该问题重复

【讨论】:

    【解决方案2】:

    嗯,有些人使用 PowerMock 来测试私有方法等,但我总是建议避免这种情况。也许你应该考虑稍微改变你的逻辑,或者更好地考虑 Kafka MockConsumer 等。

    【讨论】:

    • 我考虑过使用 MockConsumer(spring boot 变体),我的问题是我创建了一个 kafka 基础架构供我的程序员使用,而没有任何关于 kafka 的线索,我创建了一个构建器并稍微完成了整个配置愚蠢的证明。现在我支付卡夫卡支持社区的灵活性......我担心我唯一的解决方案是实际公开该方法......在我看来这是不好的做法......
    • 那么你仍然可以测试启动公共方法,并且可能只为 producerFactory 提供模拟,如果你想避免将你的 handleConsumerRecord 逻辑提取到公共。
    猜你喜欢
    • 2014-08-10
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多