新手区 2015年3月 新秀群作业-- Appium+Python+PO 设计模式 入门笔记

JennyHui · March 20, 2015 · Last by yajunzheng replied at September 26, 2018 · 4381 hits
本帖已被设为精华帖!

什么是PageObject?

  • 属于selenium的一种设计模式,套用在appium身上了(实践表明,合适,因为selenium和appium"本是同根生")
  • 个人对于PO的理解就是,页面元素 - 页面业务操作步骤的方法 - 测试用例 (我知道抽象,大家自行谷哥了解下)

下图是我的代码结构:
Data:测试数据。后期准备把代码中会所有测试数据都整合到excel或者xml内,Data文件夹就是这个用处
PO:所有Page。以Base页面为基础(看下图分析,来理解PO)
Public:一些公共的方法,比如测试报告脚本,封装好的
Result:测试结果,包括测试报告和截图
TestCase:测试用例都放这儿
run_case:测试套件,利用HTMLTestRunner.py,输出测试报告到/Result下

Base内重新封装的是基础的webdriver方法和一些你自己测试用例有需要的公用方法,PO内的其他Page都是继承自Base
appium与selenium的唯一不同就是对driver的设置上

在这里driver的调用,我感觉自己还没写好,我的需求是只在Base内定义好driver,指定好端口,所有测试用例共用一个driver,直接在测试用例内调用,我调试过了,自己python水平也是一般,没改出来,后期我再改善一下这个。

直接在Page内封装整个业务流程的方法,测试用例中代码量会少很多。(当然写在测试用例中也是可以的)
简单说明下:

  • 场景:登录业务
  • Page内:a.输入用户名 b.输入密码 c.点击登录按钮;A.登录方法(包含abc)
  • 测试用例内: 1.直接调用Page的A;2.顺序调用Page的abc 这两种方式各有各的利弊,各取所需吧

测试用例我用的是unittest
我这个demo没有写断言,没有打log,测试数据也没有放到外部文件。这些都是后期要改善的

关于报告的输出

通过测试套件去驱动HTMLTestRunner生成测试报告,并且加入了截图功能(这些都是参考selenium大神Ray的,请参照他的coding:https://coding.net/u/tsbc/p/PySelenium_PO/git

总结

demo(https://github.com/JennyHui/appiumDemo/tree/master/pythonDemo%20v1.0
整体看来框架的搭建是很简单的,但也算是五脏俱全吧(好吧,还差几个,我知道啦)。个人觉得对于框架怎么搭,用哪种设计模式,用哪种工具,选择性还是很多的。跟web类似的啊,关键字,PO,RF......各取所需吧各位,而且,不同的设计模式下,代码结构如何,也是看各人选择的。

下一阶段学习,就像我写的完善driver调用,打log,加断言,测试数据移至excel,有些人页面元素也想放到config内,这一点大家可以根据项目来权衡。

如果我可以,你也可以,因为我是菜鸟。请在一个礼拜之内搞定你的代码结构哦

共收到 56 条回复 时间 点赞

实在不会总结嗷嗷嗷

赞赞赞!!!

看到这个帖子感觉很情切,我也是python出身,同样也用webdriver 在移动端和web端做了几个自动化的项目,分享下我们的做法和思路,希望能抛砖引玉。
1,我们是采取的数据和脚本分离的形式来控制业务的逻辑和次序的,目前来看这样其实很好,首先脚本调用的是外部xls里面的数据,即使没有代码经验的人,也可以通过xls表格来进行自动化的业务参数配置。
2,对象库的管理,同样会放在xls里面,通过动态调用来实现,这样在脚本内就不会存在有大量的元素信息,一来维护不便,二来方便我们阅读。
3,我们还有点不同的是,我们将需要导入的包,都放在了一个import.py的文件里,所有脚本统一导入这个.py文件,这样节省了很多不必要的代码量。
4,我们对脚本的逻辑控制,业务参数控制均抽离出来,放在xls里,类似于UI层的控制,脚本直接调用不必每次在脚本内修改代码,造成不必要的问题和维护。

参考下我们的模式希望有所共鸣,欢迎大家指正。

受教了,又学了一个很不错的设计模式!

学习了,回头有空把ui的自动化测试做起来

赞一个,一直在用Page Object model

移动时代,改名为screen object

#3楼 @seasoncool2011 页面元素,定位方法,测试数据 都放在xls内是伐~我研究过这个~属于关键字驱动的~很赞!!设计好excel表一切万事大吉!!!赞赞赞~因为我自己自动化项目经验不多~想先把PO实践好再来整关键字~ps第三点建议不错~我收了~么么哒 👏

app路径放在哪里,如何取包安装?

目录结构很受教!多谢分享!

请教一个问题。web页面的元素是怎么获取的呢,据我所知uiautomator是无法获得webview内的具体信息的,还望分享。

这个问题已经困扰了我好几天,但似乎在别人看来都不是问题!?

我眼前的这层窗户纸希望能有人看到,并帮我捅破,谢谢了,泪奔中~~~

JennyHui #12 · April 08, 2015 作者

#11楼 @sunflower 我今天刚好也在折腾这个。webview切换进去后,我手机版本连着uiautomator看不到webview下的信息,所以我用抓包的方式去找。虽然我手机代理有点问题吧。(也可以用浏览器去开这个web去定位出页面元素)
可以参考下这个帖子:http://testerhome.com/topics/2303

#12楼 @jennyhui 谢谢回复。但不知你说的”用抓包的方式去找“和”用浏览器去开这个web去定位出页面元素“具体怎么操作呢?我已经看了http://testerhome.com/topics/2303adb这个帖子,关键是用 shell uiautomator dump 的方式大多数时候都dump不到webview里的信息(不论是纯web还是hybrid app),不知你遇到这个问题没,希望进一步探讨。

JennyHui #14 · April 09, 2015 作者

#13楼 @sunflower 是啊我也刚发现还是不行我刚在群里问了【只要到webview界面下,chrome inspect可以自动获取】~估计还是得用浏览器去打开,然后查看html元素~~~看一下这个帖子http://testerhome.com/topics/1719

#14楼 @jennyhui 这种remote debugging的方式我也尝试过,但inspect后出来一个空白页面。怀疑是我安装的插件不对,从https://developer.chrome.com/devtools/docs/remote-debugging应该能得到一些信息,但这个网址一直打不开,不知道是不是需要***才能代开啊。。。

JennyHui #16 · April 09, 2015 作者

#15楼 @sunflower 哦哦哦厉害我还在看话说你webview是国内得页面吗 如果是应该不用啊~webview也是够纠结的~~~

#16楼 @jennyhui 是啊,手机里就打开了一个baidu的首页。。。能否帮我看一下你那https://developer.chrome.com/devtools/docs/remote-debugging能打开吗?没用过***工具啊

JennyHui #18 · April 09, 2015 作者

#17楼 @sunflower 啊 我试一下 我是菜鸟呢 我还没有用用过remote调试的方式 抓取信息过 咳咳 我先看下

JennyHui #19 · April 09, 2015 作者

#17楼 @sunflower https://developer.chrome.com/devtools/docs/remote-debugging 这个网站我***可以开启来 我刚才脚本试了个demo 还报错呢(selenium.common.exceptions.WebDriverException: Message: unknown error: cannot parse capability: chromeOptions
from unknown error: unrecognized chrome option: mobileEmulation ) 容我在研究一下 咳咳

#19楼 @jennyhui 这个网站里面可能有新的chrome adb plugin,你把这个plugin添加到你的chrome浏览器里然后在地址栏输入chrome://inspect,应该就可以用了。

JennyHui #21 · April 09, 2015 作者

#20楼 @sunflower 不用安装什么插件啊!~我谷歌直接开chrome://inspect 就可以了 ~ 手机记得设计开启USB调试 ~~ 真的可以啊哈哈 好开心解决了 不过就是画面不出来不知道哪个元素对哪一个 = = 我再折腾一下 感觉离终点越来越近了

#21楼 @jennyhui 我怎么这个坎坷呢😟 ,不过这个证明这个方法确实是好用的,你用的chrome版本和手机版本是多少啊 我找找差异

JennyHui #23 · April 09, 2015 作者

#22楼 @sunflower 手机是安卓5.0的 chrome是41的

你为啥这么牛。 模板jenny 大神。

请教一下这个demo可以直接运行吗..

能不能更详细点讲解,我这边是在eclipse(安装了python插件) 建立一个自己的python project, 然后按照你的project结构导入代码文件,但是在执行时 Traceback (most recent call last):
File "/Users/fangcheng/Desktop/EclipseWorkSpace/AppiumWeb/run_case.py", line 25, in
test_case = Creatsuite()
File "/Users/fangcheng/Desktop/EclipseWorkSpace/AppiumWeb/run_case.py", line 16, in Creatsuite
discover = unittest.defaultTestLoader.discover(case_path, pattern='Test_*.py', top_level_dir=None)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/loader.py", line 190, in discover
import(start_dir)
ValueError: Empty module name

我运行示例代码也出现了如楼上所述的问题,还请楼主详细讲解一下。

JennyHui #28 · May 06, 2015 作者

#26楼 @xxfcxx
#27楼 @ellaw
目测是你路径写错了 检查一下

#28楼 @jennyhui demo的网址不能用了啊?能请各位有demo的提供一下吗

#30楼 @jennyhui 非常感谢,等着好好研究下

感谢分享!

#30楼 @jennyhui 你qq多少,加你问下具体问题

好屌,嗷嗷嗷

不错的设计模式

@halo_lan 必须的,我最佩服的厦门女测开一枚,没有之一!

@very 拿下妹子

@halo_lan 哈哈,拿不下

请问,这个在testcase里面,创建多个testcase时,是不是需要每个testcase里面都要创建一个seesion

JennyHui #40 · July 02, 2015 作者

#39楼 @lework 不是。appium启动只开一个session。测试集内的是按照你testcase顺序跑的。

JennyHui #41 · July 02, 2015 作者

#34楼 @very 认识? 😪

@jennyhui 必须认识啊。。。

JennyHui #43 · July 02, 2015 作者

#42楼 @very 你是谁呢?

看了以后 很有感触 这是我的目标啊

JennyHui #46 · July 09, 2015 作者

#45楼 @louqqson008 嗯。如果你觉得项目合适,可以用这种方式。不过我觉得PO不是最优方案。你可以了解下关键字。

@jennyhui 谢谢你的建议,目前遇到无法识别toast,并且获得toast的TEXT,而无法继续进行android自动化,可否给点建议,目前我的想法是获得toast提示的TEXT和我预期知道会得到的提示TEXT进行比较来验证用例,现在无法获得就进行不下去了

JennyHui #48 · July 10, 2015 作者

#47楼 @louqqson008 appium暂不支持哦~robotium可以~appium未来应该会支持~

请教一下,所有测试用例共用一个driver,在page页面中如何实现对该driver的调用及继承Appium已经封装好的Android方法呢(避免重新定义方法)?

妹子加个qq呗

JennyHui #51 · August 05, 2015 作者

#49楼 @laiyuncong8404
可以把driver的实例化封装在一个类方法内~(这是其中的一个方法而已)
不过如果后期希望做到不同设备不同driver跑同一份测试脚本(或者其他并发策略)就要另外对driver做其他处理(论坛内有不少帖子实现了并发的功能了)

#BasePage

//初始化driver
public AndroidDriver SetDriver() throws MalformedURLException {
try{
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), this.SetCa());

}catch (MalformedURLException e){
e.printStackTrace();
}
return driver;
}
#DashPage

/**
* 业务封装
*/


//搜索 - 收藏
public void Search(String recipe,Class name) throws IOException, InvalidFormatException {
LoggerControler log = this.MyLogger(name);
AndroidDriver driver = super.SetDriver();
this.ClickSearchBox();
this.InputRecipe(recipe);
log.info("本次搜索的食材是:"+recipe);
driver.sendKeyEvent(66);
this.ClickCollectionItem();
//this.ClickFavorite();
log.info("收藏的菜谱名为:"+this.GetRecipeName());
super.captureScreen("Search_"+recipe);
Assert.assertTrue(GetRecipeName().contains(recipe));
log.info("该Case测试通过");
}

感谢楼主分享,对于比你还新手的我来说,你的文章既是一份学习资料,也是一种鼓励。

@jennyhui
新手求指教,这句的作用是啥?
def init(self,appium_driver):
self.driver = appium_driver

kaige201314 [Topic was deleted] 中提及了此贴 22 Jul 16:54

@jennyhui 请问page object 这个driver怎么定义的呢,我现在用PO模式写,当import登录文件,调用登录函数方法时,老报:没有driver

初学,求带带

miaoyan 回复

解决没 我也一直遇到这个问题

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up