之前写过一个基于robotium+androidjunitrunner+spoon的自动化框架,详见:基于junit4+Robotium+spoon+as二次开发自动化框架,支持失败重试和失败截图,但是呢最近和 @安静的偏执 聊了一会儿发现写的还是有些瑕疵的,并给了我些建议,是关于在UI自动化中如何更好的抽离封装元素。
为了对比,我们来对比一下改进前后的效果:
目录对比:
写法对比:
@Test
public void takeCamera(){
mainPage.clickTocamera();
viewAssertions.asseetViewExist(cameraPage.camera);
cameraPage.snapShot();
}
@Test
public void takeCamera() {
holo.clickOnView(holo.getView(IdFetcher.MainActivity.camera_tab));
holo.assertViewExist(R.id.camera);
holo.clickOnView(holo.getView(IdFetcher.MainActivity.take_camera));
}
ok,那么显然改进后的写法看着更加简介,并且抽象程度更高。那么第一种写法就是今天的主角,pageobject设计模式,具体的解释可以看下文档:
https://github.com/SeleniumHQ/selenium/wiki/PageObjects
那么总结下来一句话就是:
把模块里面的元素和动作封装在一个page类里面,把业务和基本元素和操作相分离,在业务改变的时候只需要维护page类就行了。
然后我们回到上面的例子,在以前的写法,笔者是抽象出id,于是定义了一个IdFetch的类,用来抽象id,这样后续修改后只需要修改id:
public class IdFetcher{
public class MainActivity(){
//伪代码
public int camera_tab = R.id.camera_tab;
}
}
然后改进后的page页面,通过把控件和一些动作封装进一个page页面,这里有一个基类BasePage,它的作用主要是通过反射处理我自定义的java anotation,毕竟@UI这个方式找控件是比较优雅的。
public class MainPage extends BasePage {
ViewActions ViewActions;
public MainPage(Holo holo) {
super(holo);
ViewActions = new ViewActions(holo);
}
@UI(id=R.id.camera_tab)
public View camera_tab;
public void clickTocamera(){
ViewActions.click(camera_tab);
}
}
那么引入了PageObject设计模式之后,目录结构也重新设计了下:
总结
那么到这里,改造就结束了,核心的东西应该都讲到了,源码暂时不公开 :) 欢迎交流,并且最后再次感谢下 @安静的偏执 告诉我po这个很棒的模式。