开始了解和学习 Appium 也有两个月了, 期间工作原因断断续续的一直都在论坛查看各位同行的帖子, 受益良多. 虽然也工作在测试自动化有段时间, 但是对于开源的工具一直投入的时间不足, 本着开源的原则, 把自己这段时间了解和学习的体会化为帖子, 分享一下, 本帖子中所引用的代码都可以在 https://github.com/PandaSense/mtesense 上下载, 由于接触的时间不长加上懒惰, 代码中有些方法来自网络和其他同行的框架, 特此声明. 本例中所有代码均为 java 编写, 例子写代码非常简单, 并且也可以简单的使用于 Selenium 的自动化测试, 仅为抛砖引玉和学习之用.
框架取名为 Mtesense , Mte 可以理解为 Make Testing Easy, 基本组成为 java+Appium+Selenium+junit, 如果想实现持续集成可以自行添加 ANT 或者 Maven 的脚本. 类似于 PO 模式设计, 并不完全具有普遍性, 具体方式应与实际项目为准.
基本结构
框架结构
结构说明
config : 主要的配置文件, 包括 database.properties, mtesense.properties, yaml 文件 ( element 信息, MteSenseLocator 和 YamlUtil 配合读取 yaml 文件中信息)
lib : 所有需要的第三方资源, 包括所需的所有的 jar 文件等.
log : log4j 日志目录, 可以自己编写 ANT 文件输出为 html 格式 log 文件.
report : ReportUtil 富文本格式 report 输出目录, 请自行参考代码,实现非常简单, 类似与一般打印的 log, 生成 rtf 扩展文件, 支持 MS office 或者 openoffice 编辑,包括文本和图片信息等.
screen : 截图路径, 脚本中可以用 captureScreenshot(String filepath) 或者 captureScreenshotByCase() 截图, 具体实现请参考 MteSenseCore 文件.
app : android 和 ios app 存放路径.
必要信息
MteSense.java : 所有 webdriver 初始化都在这里. MteSenseBaseCase.java 调用此文件可以通过 传如关键字 ios, android 或者 firefox 等,直接创建 webdriver. 也可以通过传入 DesiredCapabilities 和 url, driverType 参数来创建 webdriver.
MteSenseBaseCase.java : 测试用例有次开始 包括初始化 webdriver 等常用方法, 具体实现可以用过下面的例子截图理解.
com.mte.common.base package : 这里有些 java 文件 暂时只有简单的实现, 后续会不断添加更多的实现,
com.mte.util package : 所有的通用工具类方法都在这里.
page package : 存放对应界面的测试所需的 element.
task : 为业务逻辑的分块实现, 基于具体的业务需求.
testcase : 测试用例的代码实现,task 中具体的业务拼接.
关于数据准备
可以通过工具类去读取 excel 或者是 java property 文件去实现, 框架中对于数据库的操作, 仅包含了 JDBC 的 type4 直连方式简单粗暴. 至于需要 orm 类数据库持久层, 请自行添加.
关于 hybrid 调试
不多说, chrome 或者 safari 自带的 devtool.
例子使用的 app, 为 Appium 官方的 WebViewApp.app, 需要在本机的 xcode 编译后在拷贝到 app 目录下. 可以使用 下面的命令在对应的 app 目录下编译.
xcodebuild -scheme yourapp -destination 'platform=iphonesimulator,name=iPhone 5s' -derivedDataPath build
testcase
public class WebViewAppItclTestCase extends MteSenseBaseCase {
private String testCaseName = this.getClass().getSimpleName();
private WebViewAppHomeTask homeTask;
@Before
public void setUp() throws Exception {
beforeClass("ios");
asBaseCore.setTestCaseName(testCaseName);
}
@Test
public void testMain() throws Exception {
homeTask=new WebViewAppHomeTask(asBaseCore);
homeTask.doSearchByUrl("cn.bing.com");
homeTask.changeToWebView();
homeTask.doBingSearch("baidu");
}
@After
public void tearDown() throws Exception {
afterClass();
}
}
task
public class WebViewAppHomeTask extends MteSenseBaseTask {
private Logger logger = Logger.getLogger(WebViewAppHomeTask.class);
private WebViewAppHomePage homepage;
public WebViewAppHomeTask(MteSenseCore senseCore) {
super(senseCore,null);
homepage=new WebViewAppHomePage(asCore);
}
public void doSearchByUrl(String url){
logger.info("Start to run doSearchByUrl");
WebElement element = homepage.getUrlField();
asCore.sendKeys(element, url);
asCore.hideKeyboard();
asCore.captureScreenshotByCase();
element = homepage.getGoButton();
asCore.click(element);
asCore.pause(3000);
asCore.captureScreenshotByCase();
}
public void changeToWebView(){
logger.info("Start to run changeToWebView");
Set<String> contextNames = asCore.getContextHandles();
for (String contextName : contextNames) {
if (contextName.contains("WEBVIEW")) {
asCore.context(contextName);
}
}
}
public void doBingSearch(String url){
logger.info("Start to run doBingSearch");
WebElement element = homepage.getBingSearchField();
element.sendKeys("baidu");
element.submit();
asCore.hideKeyboard();
asCore.pause(3000);
asCore.captureScreenshotByCase();
}
}
page
public class WebViewAppHomePage extends MteSenseBasePage {
private Logger logger = Logger.getLogger(WebViewAppHomePage.class);
MteSenseLocator locator = new MteSenseLocator("./config/mtesenseexample.yaml");
private String pageName = this.getClass().getSimpleName();
public String getPageName() {
return pageName;
}
public WebViewAppHomePage(MteSenseCore senseCore) {
super(senseCore);
}
public WebElement getUrlField() {
return asCore.findElement(locator.getLocator("urlfield"));
}
public WebElement getGoButton() {
return asCore.findElement(locator.getLocator("go"));
}
public WebElement getBingSearchField() {
return asCore.findElement(locator.getLocator("bingsearchfield"));
}
}
例子的实现只有简单的几步,实际的项目中会很复杂, 设计方式也会有所不同, 对于有自动化测试经验的同行来说, 也好理解. 之所以分成三块 (page task testcase) 来实现具体的测试用例, 是根据通常的项目实际来的, 一般整个项目的测试过程会分为几个阶段, 分成模块会比较好控制, 同时也为了团队合作, 各司其职吧. 至于持续集成或者有其他的特殊需求可以自行添加,常用的工具使用和常规的代码编写对于自动化测试人员来说不应该成为问题, 篇幅所限, 没有说的很详细请大家谅解, 欢迎大家指正.