最近刚刚接触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的代码比较功能非常强大,但手动合并还是麻烦。
但是,所得到的回报就是测试非常方便,非常方便!
在我没有发现一个非常棒的工具之前,我还是暂时使用这种方式,直到项目的结束。
或许在结束之前,我就会因为模拟类的繁多而停止使用这种方式,
也或许直到结束,我都会一直使用这种方式,而且发现它会越来越好用。