一. 介绍
JFCUnit 是一款在 JUnit 基础上针对 Swing GUI 扩展的单元测试工具。在同一个应用程序中,我们可以通过组件发现方法查找到组件,模拟用户动作触发组件事件来提供测试驱动,通过断言验证组件状态是否正确。
优点:
Ø 继承了 JUnit ,具有 JUnit 进行单元测试的所有优点;
Ø 提供了一系列 GUI 组件发现方法及用户动作模拟方法。
在读下面的内容之前,您可以先下载“ JFCUnit Example ”。这是一个完整的 eclipse 工程,首先运行其中的一个例子,可以使您对 JFCUnit 有一个感官上的了解。
二. JFCUnit API
说明:此处仅是简单介绍,具体使用可以参见“ JFCUnit Example ”。
1. GUI 组件发现类
a.
通用命名组件发现类: NamedComponentFinder
(java.lang.Class cls, java.lang.String name)
这个类使用最多,也最容易,但需要在我们的GUI程序中将组件命名(如
cancelBtn.setName(“cancelBtn”) ) 。
示例代码
:
NamedComponentFindercancelBtnFinder = new NamedComponentFinder(JButton.class, "cancelBtn");
JButton cancelBtn = (JButton) cancelBtnFinder.find();
assertNotNull("cancelBtn not found!", cancelBtn);
assertEquals(true, cancelBtn.isEnabled());
b. 其它组件发现类:
这一些类主要是针对一些特定的 GUI 组件提供了一些特殊的查找方法。主要有:
DialogFinder
FrameFinder
JLabelFinder
等等。具体使用可以查找 API 文档,在 junit.extensions.jfcunit 下的 doc 文档中。
示例代码
:
FrameFinder frameFinder = new FrameFinder("FrameDemo"); // 字符串为 Frame 标题
List frames = frameFinder.findAll();
assertEquals("frames size wrong",1,frames.size());
JFrame frame = (JFrame)frames.get(0);
assertNotNull("frame is null !",frame);
2. 用户动作模拟类
这些类主要有:
AbstractMouseEventData
DragEventData
JComboBoxMouseEventData
JListMouseEventData
JTabbedPaneMouseEventData
等等。这些类的使用大同小异。在 “ JFCUnit Example ”也有详细的使用例子。下面以表格为例:
finder.setName( "table" );
JTable table = (JTable)finder.find(frame, 0); // 从 Frame 中查找到表格
assertNotNull( "table not found !" ,table);
// 模拟双击单元格
JTableMouseEventDatatableEvent= new JTableMouseEventData( this ,table,1,2,2);
helper .enterClickAndLeave(tableEvent);
this .flushAWT(); // 执行事件派发队列中的线程 , 保让事件已经被响应。
// 模拟改变单元格的文本值
helper .enterClickAndLeave(tableEvent);
this .flushAWT();
helper .sendKeyAction( new KeyEventData( this ,tableEvent.getComponent(),KeyEvent. VK_DELETE ));
helper .sendString( new StringEventData( this ,tableEvent.getComponent(), "" ));
helper .sendString( new StringEventData( this ,tableEvent.getComponent(), "wukaichun" ));
this .flushAWT();
// 模拟多选表格行
JTableMouseEventDatasrcEvent = new JTableMouseEventData( this ,table,1,2,1);
JTableMouseEventDatasinkEvent = new JTableMouseEventData( this ,table,2,2,1);
helper .enterDragAndLeave( new DragEventData( this ,srcEvent,sinkEvent));
this .flushAWT();
三. 配置
对于实际 GUI 项目,往往需要按界面分别进行测试。为了多个测试用例共用测试环境(不必每次都启动项目),可以将被测工程与 JUnit 一起启动。而后在 JUnit 的 swingUI 中选取用例执行。
如:
package person.jfcunit.test;
import junit.swingui.TestRunner;
public class MainTest {
public static void main(String[] args) {
LoginScreen.main( new String[]{}); // 启动被测 GUI 程序
TestRunner.main( new String[]{}); // 启动 JUnit
}
}
注意:
3. 启动配置中除主函数变为 MainTest 外,其它配置与被测工程一样;
4. 如果使用 JUnit swingui 测试界面,为了保证所有的组件都为同一加载器加载,需要将被测类改为默认加载器加载。
a. 找到文件 excluded.properties ,在 junit.jar 的 junit.runner 下;
b. 修改 excluded.properties ,将被测试类添加到 excluded 中,如下:
#
# The list of excluded package paths for the TestCaseClassLoader
#
excluded.0=sun.*
excluded.1=com.sun.*
excluded.2=org.omg.*
excluded.3=javax.*
excluded.4=sunw.*
excluded.5=java.*
excluded.6=org.w 3c .dom.*
excluded.7=org.xml.sax.*
excluded.8=net.jini.*
excluded.9=org.apache.commons.logging.*
excluded.9=person.*
在这里列出的包将不使用 TestCaseClassLoader 加载,而是由默认加载器加载。如最后一行“ excluded.9=person.* ”,我们将 person 包中的类排除在 TestCaseClassLoader 加载之外。
这个时候,运行 MainTest ,您就可以对您的项目进行测试了。
四. 结束语
写这篇文章的启示是对当前公司的 GUI 网管进行单元测试时的总结。 JFCUnit 有一定的局限性,它只能针对于扩展了 Component 的 GUI 组件进行测试。对于 ilog 这类直接由 Object 继承来的 GUI 则需要使用者自己扩展。但其简单和易用性应该能满足大多数实际项目的了。
在这里共享出来,希望对使用 Swing 的同仁能有点帮助。文章中有不明白或不正确之处,请不吝赐教。谢谢! Email:[email protected] 。
五. 参考资料
JFCUnit 测试 GUI 的一个实例(配置篇) 可以了解在 eclipse 下 JFCUnit 的安装及配置。
自作聪明的 junit.swingui.TestRunner 其中解释了使用 swing ui 界面时的类加载器问题,值得一看。