如何测试调用私有方法的匿名内部类
我们有一堆类监听来自服务器的事件然后响应它们。例如:
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);
// ...
}
}
这是我们正在做的事情的一个虚构的例子。以下是我看到的问题:
- 我想测试handleEvent以确保它正在执行它应该执行的操作,但我不能,因为它是私有的。
- 我还想检查是否也添加了某些内容到缓存中,但这似乎也很困难,因为缓存是私有成员,而且我不想添加不必要的 getter 方法。
- 我还想测试匿名类的 onEvent 方法内的代码。
现在,我所做的是将所有逻辑从匿名类移至handleEvent 方法,并将handleEvent 包设为私有(我的单元测试位于同一个包中)。尽管我想检查缓存的内容,但我并没有这样做。
有人对更好、更可测试的设计有什么建议吗?
We have a bunch of classes that listen for events from the server and then respond to them. For example:
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);
// ...
}
}
Here's a made-up example of the kind of thing we are doing. Here are the problems I see:
- I'd like to test handleEvent to make sure it's doing what it is supposed to but I can't because it's private.
- I'd also like to check that something got added to the cache too but that also seems difficult since cache is a private member and I don't want to add a needless getter method.
- I'd also like to test the code inside the anonymous class's onEvent method.
For now, what I did was move all logic from the anonymous class to the handleEvent method, and I made handleEvent package private (my unit test is in the same package). I'm not checking the contents of the cache although I want to.
Does anyone have any suggestion for a better design that is more testable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我可能会提取一个 EventCache 组件。您可以将测试替换为对缓存事件进行计数或记录任何感兴趣的内容的实现。
我可能不会改变handleEvent 的可见性。您可以实现一个仅从测试用例中引发事件的 ServerCommunication。
I would probably extract a EventCache component. You can replace this for your test with an implementation that counts the cached events or records whatever is of interest.
I probably would not change the visibility of handleEvent. You could implement a ServerCommunication that just raises the event from the test case.
嗯,这里有两种方法:黑盒和白盒。
黑盒测试建议您应该只测试公开可见的更改。这个方法有明显的效果吗? (有些东西不会 - 缓存是一个明显的例子,它们可以提高性能,但在其他情况下可能是不可见的。)如果是这样,请测试一下。如果没有,请测试它是否具有负面效果 - 这很可能只是加强其他测试的情况。
白盒测试表明,也许您可以添加一个包级方法来进行测试,例如,
通过在名称中添加“用于测试”,您可以让每个人都清楚地知道他们应该这样做不要从生产代码中调用它。您可以使用注释来指示相同的事情,甚至可能有一些构建规则来确保生产中的任何内容都不会调用此类方法。
这最终会变得更加脆弱 - 与实现更加相关 - 但它确实使彻底测试代码变得更容易,IMO。就我个人而言,我倾向于对单元测试进行白盒测试,而集成测试绝对应该更加黑盒。其他人则更加教条地只测试公共 API。
Well, there are two approaches here: black box and white box.
Black box testing suggests you should only test the publicly visible changes. Does this method have any observable effect? (Some things don't - caches being an obvious example where they improve performance but may otherwise be invisible.) If so, test that. If not, test that it isn't having a negative effect - this may well just be a case of beefing up other tests.
White box testing suggests that maybe you could add a package-level method for the sake of testing, e.g.
By putting "for testing" in the name, you're making it obvious to everyone that they shouldn't call this from production code. You could use an annotation to indicate the same thing, and perhaps even have some build rules to make sure that nothing from production does call such a method.
This ends up being more brittle - more tied to the implementation - but it does make it easier to test the code thoroughly, IMO. Personally I err on the side of white box testing for unit tests, whereas integration tests should definitely be more black box. Others are rather more dogmatic about only testing the public API.
我假设您的 EventManager 是单例,或者您可以访问正在测试的类的特定实例。
1 - 我想你可以将事件发送到你的班级。您的方法是私有的,其他人不能调用它,那么发送一个事件就足够了。
2 - 如果你确实需要的话,你可以通过反思来访问它。您的测试将取决于特定的实现。
3 - 您实际上想测试什么?如果要确保调用此方法,可以通过反射将 EventListener 替换为另一个 EventListener 对象(并最终从新侦听器中调用第一个侦听器的 onEvent 方法)。但您的问题似乎更多的是关于代码覆盖率而不是实际的单元测试。
I assume your EventManager is a singleton, or you have access to the particular instance of the class you're testing.
1 - I suppose you can send events to your class. Your method is private, and nobody else can call it, then sending an event should be enough.
2 - You can access that through reflection, if you really need to. Your test would depend on a particular implementation.
3 - What would you like to test, actually? If you want to be sure that this method is called, you can replace the EventListener with another EventListener object through reflection (and eventually call the onEvent method of the first listener from your new listener). But your question seems to be more about code coverage than actual unit-testing.
有时,当遇到我想测试的私有方法时......它们只是尖叫着成为另一个对象上的公共方法。
如果您认为 HandleEvent 值得单独测试(而不是通过 onEvent 处理),一种方法是将 HandleEvent 作为新/不同对象的公共方法公开。
Sometimes, when coming across private methods that I want to test... they are simply screaming to be public methods on another object.
If you believe that HandleEvent is worth testing in isolation (and not through onEvent processing), one approach would be to expose HandleEvent as a public method on new/different object.
利用这个机会将代码分解为更小、更集中(默认访问)的类。测试只是代码的另一个客户端。
请注意,匿名内部类的
onEvent
方法实际上是可以访问的,因此调用它应该不成问题。Use this opportunity to break the code up into smaller more focussed (default access) classes. A test is just another client for the code.
Note that the anonymous inner class'
onEvent
method is actually accessible, so calling it should not be a problem.