我正在编写类似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
答案 0 :(得分:12)
看this:
FEST是一系列库,在Apache 2.0 license下发布,其任务是简化软件测试。它由各种模块组成,可与TestNG或JUnit ...
一起使用
答案 1 :(得分:11)
注意,一般来说,对UI内容进行单元测试总是很困难,因为你必须嘲笑很多不可用的东西。
因此,开发应用程序(任何类型)时的主要目的始终是尝试尽可能地将UI内容与主应用程序逻辑分开。在这里拥有强大的依赖性,使单元测试变得非常困难,基本上是一场噩梦。这通常通过使用类似MVC方法的模式来实现,其中您主要测试控制器类,而视图类除了构建UI并将其操作和事件委派给控制器之外什么都不做。这将责任分开,使测试更容易。
此外,您不一定要测试框架提供的内容,例如测试事件是否被正确触发。你应该自己测试你正在编写的逻辑。
答案 2 :(得分:2)
检查uispec4j项目。这就是我用来测试我的用户界面。
答案 3 :(得分:2)
我认为测试的问题是揭示了代码的问题。决定它是否在调度线程中运行应该不是模型的工作,这是太多的责任。它应该只是做它的通知工作,让一个调用组件决定是直接调用它还是调用它。该组件应该在知道Swing线程的代码部分。该组件应该只知道文件等。
答案 4 :(得分:1)
我只和jMock合作了两天......所以如果有更优雅的解决方案,请原谅。 :)
看起来你的FileTableModel依赖于SwingUtilities ......你考虑过嘲笑你使用的SwingUtilities吗?一种闻起来像黑客但会解决问题的方法是创建一个接口,比如ISwingUtilities,并实现一个虚拟类MySwingUtilities,它只是转发到真正的SwingUtilities。然后在您的测试用例中,您可以模拟接口并为isEventDispatchThread返回true。
@Test
public void testEventsNow() throws IOException {
IFile testDir = mockDirectoryStructure();
final ISwingUtilities swingUtils = context.mock( ISwingUtilities.class );
final FileSystemEventsListener listener =
context.mock(FileSystemEventsListener.class);
context.checking(new Expectations()
{{
oneOf( swingUtils ).isEventDispatchThread();
will( returnValue( true ) );
oneOf(listener).currentDirectoryChanged(with(any(IFile.class)));
}});
FileTableModel model = new FileTableModel(testDir);
model.setSwingUtilities( swingUtils ); // or use constructor injection if you prefer
model.switchToInnerDirectory(1);
}