Swing 组件的单元测试
我正在编写一个类似 TotalCommander 的应用程序。我有一个单独的文件列表组件及其模型。模型支持侦听器并以以下方式发出诸如 CurrentDirChanged
等事件的通知:
private void fireCurrentDirectoryChanged(final IFile dir) { if (SwingUtilities.isEventDispatchThread()) for (FileTableEventsListener listener : tableListeners) listener.currentDirectoryChanged(dir); else { SwingUtilities.invokeLater(new Runnable() { public void run() { for (FileTableEventsListener listener : tableListeners) listener.currentDirectoryChanged(dir); } }); } }
我为此编写了一个简单的测试:
@Test public void testEvents() throws IOException { IFile testDir = mockDirectoryStructure(); final FileSystemEventsListener listener = context.mock(FileSystemEventsListener.class); context.checking(new Expectations() {{ oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); }}); FileTableModel model = new FileTableModel(testDir); model.switchToInnerDirectory(1); }
这不起作用,因为没有 EventDispatchThread
。有什么方法可以在无头构建中对此进行单元测试吗?
java swing jmock 单元测试
I am writing a TotalCommander-like application. I have a separate component for file list, and a model for it. Model support listeners and issues a notification for events like CurrentDirChanged
etc. in following manner:
private void fireCurrentDirectoryChanged(final IFile dir) { if (SwingUtilities.isEventDispatchThread()) for (FileTableEventsListener listener : tableListeners) listener.currentDirectoryChanged(dir); else { SwingUtilities.invokeLater(new Runnable() { public void run() { for (FileTableEventsListener listener : tableListeners) listener.currentDirectoryChanged(dir); } }); } }
I've written a simple test for this:
@Test public void testEvents() throws IOException { IFile testDir = mockDirectoryStructure(); final FileSystemEventsListener listener = context.mock(FileSystemEventsListener.class); context.checking(new Expectations() {{ oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); }}); FileTableModel model = new FileTableModel(testDir); model.switchToInnerDirectory(1); }
This does not work, because there is no EventDispatchThread
. Is there any way to unit test this inside the headless build?
unit-testing java swing jmock
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
请注意,一般来说,对 UI 内容进行单元测试总是很困难,因为您必须模拟很多不可用的内容。
因此,开发(任何类型)应用程序时的主要目标始终是尝试尽可能地将 UI 内容与主应用程序逻辑分开。这里有很强的依赖性,使单元测试变得非常困难,基本上是一场噩梦。这通常通过使用诸如 MVC 一种方法,主要测试控制器类和视图类,除了构建 UI 并将其操作和事件委托给控制器外,什么也不做。这分离了职责并使测试更容易。
此外,您不必测试框架已经提供的东西,例如测试事件是否正确触发。您应该自己测试您编写的逻辑。
Note, generally speaking unit testing on UI stuff is always difficult because you have to mock out a lot of stuff which is just not available.
Therefore the main aim when developing applications (of any type) is always to try to separate UI stuff from the main application logic as much as possible. Having strong dependencies here, make unit testing really hard, a nightmare basically. This is usually leveraged by using patterns like a MVC kind of approach, where you mainly test your controller classes and your view classes do nothing than constructing the UI and delegating their actions and events to the controllers. This separates responsibilities and makes testing easier.
Moreover you shouldn't necessarily test things which are provided by the framework already such as testing whether events are correctly fired. You should just test the logic you're writing by yourself.
看看这个:
Look this:
检查 uispec4j 项目。这就是我用来测试我的用户界面的东西。
www.uispec4j.org
Check the uispec4j project. That's what I use to test my UIs.
www.uispec4j.org
我只使用 jMock 两天...所以如果有更优雅的解决方案,请原谅。 :)
看来您的 FileTableModel 依赖于 SwingUtilities...您是否考虑过模拟您使用的 SwingUtilities?一种听起来像黑客但可以解决问题的方法是创建一个接口(ISwingUtilities),并实现一个虚拟类 MySwingUtilities,该类简单地转发到真正的 SwingUtilities。然后在您的测试用例中,您可以模拟接口并为 isEventDispatchThread 返回 true。
I've only been working with jMock for two days... so please excuse me if there is a more elegant solution. :)
It seems like your FileTableModel depends on SwingUtilities... have you considered mocking the SwingUtilities that you use? One way that smells like a hack but would solve the problem would be to create an interface, say ISwingUtilities, and implement a dummy class MySwingUtilities that simply forwards to the real SwingUtilities. And then in your test case you can mock up the interface and return true for isEventDispatchThread.
我认为测试的问题在于揭示了代码的问题。决定它是否在调度线程中运行实际上不应该是模型的工作,这有太多的责任。它应该只执行通知工作,并让调用组件决定是直接调用它还是调用Later。该组件应该位于了解 Swing 线程的代码部分。该组件应该只了解文件等。
I think the problem with testing is revealing a problem with the code. It shouldn't really be the model's job to decide whether it's running in the dispatch thread, that's too many responsibilities. It should just do its notification job and let a calling component decide whether to call it directly or to invokeLater. That component should be in the part of the code that knows about Swing threads. This component should only know about files and such.