【问题标题】:How to test an anonymous inner class that calls a private method如何测试调用私有方法的匿名内部类
【发布时间】:2010-07-16 07:26:00
【问题描述】:

我们有一堆类来监听来自服务器的事件然后响应它们。例如:

class EventManager {
    private Set<Event> cache = new HashSet<Event>();

    private EventListener eventListener = new EventListener() {
        void onEvent(Event e) {
          if (e instanceof MyEvent || e instanceof YourEvent) {
            handleEvent(e);
          }  
        }
    }

    public EventManager(ServerCommunication serverComm) {
        serverComm.addListener(eventListener);
    }

    private handleEvent(Event e) {
        // handle the event...
        // ...
        cache.add(cache);
        // ...
    }
}

这是我们正在做的事情的虚构示例。以下是我看到的问题:

  1. 我想测试 handleEvent 以确保它正在做它应该做的,但我不能,因为它是私有的。
  2. 我还想检查是否也将某些内容添加到缓存中,但这似乎也很困难,因为缓存是私有成员,我不想添加不必要的 getter 方法。
  3. 我还想测试匿名类的 onEvent 方法中的代码。

目前,我所做的是将所有逻辑从匿名类移至 handleEvent 方法,并将 handleEvent 包设为私有(我的单元测试在同一个包中)。虽然我想检查缓存的内容,但我没有检查。

有没有人对更好的、更可测试的设计有任何建议?

【问题讨论】:

  • EventManager上的第二种方法应该是public EventManager(ServerCom....)?
  • 它已经是公开的了...不过我已经改了名字,我无意中将构造函数命名为 EventListener(..)。
  • 这是我的解决方案。 ServerCommunication 使用 Mockito 进行模拟。我使用 ArgumentCaptor 来获取侦听器,然后将其称为 onEvent 方法。我最初不喜欢这个解决方案,因为 Mockito 说 ArgumentCaptors 应该只用于验证,而不是用于存根,但是,我不同意他们的推理(他们说“它使测试的可读性降低。”)我不要费心直接测试缓存。之后我会做其他事情,这取决于缓存中的内容。

标签: java unit-testing testing junit


【解决方案1】:

我可能会提取一个 EventCache 组件。您可以用计算缓存事件或记录任何感兴趣的内容的实现来替换您的测试。

我可能不会改变handleEvent 的可见性。您可以实现一个 ServerCommunication,它只从测试用例中引发事件。

【讨论】:

    【解决方案2】:

    嗯,这里有两种方法:黑盒和白盒。

    黑盒测试建议您只测试公开可见的更改。这种方法有什么明显的效果吗? (有些东西没有——缓存是一个明显的例子,它们可以提高性能,但可能不可见。)如果是这样,测试一下。如果没有,请测试它没有负面效果 - 这很可能只是加强其他测试的情况。

    白盒测试建议您可以添加一个包级别的方法来进行测试,例如

    Cache getCacheForTesting()
    

    通过在名称中添加“用于测试”,您可以让每个人都明白他们不应该从生产代码中调用它。您可以使用注解来指示相同的事情,甚至可能有一些构建规则来确保生产环境中不会调用这样的方法。

    这最终会变得更加脆弱 - 与实现更相关 - 但它确实 使彻底测试代码变得更容易,IMO。就我个人而言,我在单元测试的白盒测试方面犯了错误,而集成测试绝对应该是更多的黑盒测试。其他人对于测试公共 API 则更加教条。

    【讨论】:

      【解决方案3】:

      我假设您的 EventManager 是一个单例,或者您可以访问您正在测试的类的特定实例。

      1 - 我想你可以向你的班级发送事件。你的方法是私有的,没有其他人可以调用它,那么发送一个事件就足够了。

      2 - 如果你真的需要,你可以通过反射来访问它。您的测试将取决于特定的实现。

      3 - 实际上,您想测试什么?如果你想确保调用了这个方法,你可以通过反射将 EventListener 替换为另一个 EventListener 对象(并最终从你的新监听器中调用第一个监听器的 onEvent 方法)。但是您的问题似乎更多是关于代码覆盖率而不是实际的单元测试。

      【讨论】:

        【解决方案4】:

        有时,当遇到我想测试的私有方法时......他们只是在尖叫要成为另一个对象的公共方法。

        如果您认为 HandleEvent 值得单独测试(而不是通过 onEvent 处理),一种方法是将 HandleEvent 公开为新/不同对象的公共方法。

        【讨论】:

          【解决方案5】:

          利用这个机会将代码分解为更小、更集中(默认访问)的类。测试只是代码的另一个客户端。

          请注意,匿名内部类的onEvent 方法实际上是可以访问的,因此调用它应该没有问题。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-11-01
            • 1970-01-01
            • 1970-01-01
            • 2016-08-05
            • 1970-01-01
            • 2011-09-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多