最近刚刚接触RCP这个东西,其中如何进行单元测试让我头疼了好几天。
搜索了一下,倒是发现了许多测试工具,但是,要么是收钱的,要么是安装不方便,要么是
使用麻烦。
总之,没找到好用的。
最后,无奈之下,决定使用最古老的方式—–MOCK!这绝对不是一个好的方式,但是,如果你想
自如的进行单元测试,倒是一个可以考虑的方式。
RCP程序不同于WEB程序,RCP的程序就是普通的JAVA类,运行的时候也不需要额外的服务器。
那么,我们能不能象运行一个普通的JAVA类那样来运行一个RCP程序呢?
答案是否定的,因为RCP运行的时候需要RCP的环境。
那么我们就来MOCK!
例如我有一个 Editor 类,
-
public
class
NewOrderEditor
extends
EditorPart { -
private
Text text_1; -
public
void
createPartControl(Composite parent) { - …..
- …..
- }
- }
首先,我把这个类拷贝到测试目录里,然后改个名字,例如叫 NewOrderEditorMock.java。
然后,开始Mock,原则就是脱离一切 swt 等组件!
所有的 Text, Button, Table, TableItem, CheckBoxTableViewer 全部都自己写一个模拟类,
其中所需要的方法也实现一个模拟的。
例如这就是一个模拟类:
-
public
class
CheckboxTableViewer { -
private
Table table =
new
Table(); -
public
static
CheckboxTableViewer newCheckList(Composite parent,
int
style) { -
return
new
CheckboxTableViewer(); - }
-
public
Table getTable() { -
return
table; - }
-
public
Object[] getCheckedElements() { -
// TODO Auto-generated method stub
- java.util.List<TableItem> itemList = table.getTableItemList();
-
java.util.List elementList =
new
ArrayList(); -
for
(TableItem item : itemList ) { -
if
(item.isCheck()) { - elementList.add(item.getData());
- }
- }
-
if
(elementList.size()==
0
) { -
return
null
; - }
-
return
elementList.toArray(
new
Object[elementList.size()]); - }
-
public
void
selectLine(
int
line) { - TableItem tableItem = table.getTableItemList().get(line);
-
tableItem.setCheck(
true
); - }
- }
-
public
class
Table { -
List<TableColumn> tableColumnList =
new
ArrayList<TableColumn>(); -
List<TableItem> tableItemList =
new
ArrayList<TableItem>(); -
public
void
setLinesVisible(
boolean
b) { - }
-
public
void
setHeaderVisible(
boolean
b) { - }
-
public
void
setBackground(Color color) { -
// TODO Auto-generated method stub
- }
-
public
void
setLayoutData(GridData gd_tle_resultset) { -
// TODO Auto-generated method stub
- }
-
public
void
removeAll() { -
// TODO Auto-generated method stub
- tableColumnList.clear();
- tableItemList.clear();
- }
-
public
TableItem getItem(
int
selectIndex) { -
// TODO Auto-generated method stub
-
return
tableItemList.get(selectIndex); - }
-
public
void
remove(
int
[] index) { -
// TODO Auto-generated method stub
-
for
(
int
i =
0
; i< tableItemList.size(); i++) { -
for
(
int
j =
0
; j < index.length; j++) { -
if
(i==index[j]) { - tableItemList.remove(i);
- i–;
-
break
; - }
- }
- }
- }
-
public
int
getItemCount() { -
// TODO Auto-generated method stub
-
return
tableItemList.size(); - }
-
public
TableItem[] getItems() { -
// TODO Auto-generated method stub
-
return
tableItemList.toArray(
new
TableItem[tableItemList.size()]); - }
-
public
int
getColumnCount() { -
// TODO Auto-generated method stub
-
return
tableColumnList.size(); - }
-
public
TableColumn getColumn(
int
n) { -
// TODO Auto-generated method stub
-
return
tableColumnList.get(n); - }
-
public
List<TableColumn> getTableColumnList() { -
return
tableColumnList; - }
-
public
void
setTableColumnList(List<TableColumn> tableColumnList) { -
this
.tableColumnList = tableColumnList; - }
-
public
List<TableItem> getTableItemList() { -
return
tableItemList; - }
-
public
void
setTableItemList(List<TableItem> tableItemList) { -
this
.tableItemList = tableItemList; - }
- }
这么做确实很麻烦,不过好在很多方法都很容易模拟 —– 这不是你的水平高,而是因为那些
组件使用了MVC模式,写模拟方法的时候,根本无须考虑视图的问题。
至于鼠标点击按钮,就更容易了—–因为那好比直接调用类里的一个方法!
编写模拟的过程并不容易,因为有的时候,你会发现你要模拟更多的类—-在这个过程中,我
怀疑我做的到底有没有意义?不过我还是做了,因为只有做过了,才能知道。
终于,模拟类都写完了,我开始测试一个 editor 界面。
测试类真的是太好写了,我可以和程序中的任何一个类进行交互,因为目前这个模拟的界面
就是一个普通的类。
这其中我测试出了一些BUG,进行了修改。也测试出了一些模拟类的问题,当然也对其进行了
修改。
当全部的测试通过以后,我再使用eclipse的比较功能,把模拟的界面类和真正的界面类进行了
代码合并。
之后 …. …..
我还有下一个界面要进行编码,在编码之前,我重复之前的步骤,复制了一个模拟类,把 swt
等相关的东西删除了,导入模拟的类。这次我没那么麻烦,因为很多东西在上一个过程里都创建
好了。
直到这里,我仍然不知道我所做的是否有意义,因为这么做很麻烦—我每次都需要合并模拟类
和真正的类的代码。Eclipse的代码比较功能非常强大,但手动合并还是麻烦。
但是,所得到的回报就是测试非常方便,非常方便!
在我没有发现一个非常棒的工具之前,我还是暂时使用这种方式,直到项目的结束。
或许在结束之前,我就会因为模拟类的繁多而停止使用这种方式,
也或许直到结束,我都会一直使用这种方式,而且发现它会越来越好用。