Page Object设计模式实战(3)

PO模式
po其实就是封装的概念
优点:清晰稳定
页面发生变化的时候,只需要改变细节就好了,对外暴露接口其实是没有变的
六大原则:
1.公共方法应该对应页面提供的服务
2.不要暴露过多页面细节
3.断言不要放在pageobject中,混在一起写会引起混乱,页面改动的时候容易混乱;让断言去调封装的细节就好了
4.应该尽量返回一个页面,点击按钮可能会弹出一个新的页面
5.只对关键元素建模
6.不同的结果可以返回不同的方法 
企业微信实战
具体代码如下:git地址:https://github.com/zhaitiantian1/Enterprise-WeChat
其中需要注意的是:⚠️⚠️❗️
1.注意:隐式等待是全局的,因此在初始化driver的时候设置的
2. 而显式等待则可以特殊对象特殊对待
3.po设计模式下: 如果页面变了,不需要在test _case中修改代码
4. basepage通常用来封装driver有关的设置,封装定位元素(查找元素)
5. 代码中的reuse让一个类告诉我们,如果reuse为True,就说明使用浏览器的复用,如果为false,就初始化一个新的浏览器
6.把driver提取出来,把driver变成私有变量_driver,不对外暴露具体的细节,符合po原则
7.为什么进行封装
   1) 把driver集中在basepage中是为了以后 便于统一修改,以后用appium也可以进行这样的封装,频繁的换底层的时候比较方便
   2) 将driver变成私有的变量,封装find后,不会被子类随便改造,只会让basepage进行改造
    3)想再里面加日志什么的,就可以直接在find ()中加入日志,不需要改变页面上其他引用find()函数的地方修改了
   4)也是为了便于管理
   5)使用封装,以后万一做框架,要有一个核心就是basepage,以后无论测知乎、简书还是其他网站,都可以使用这套核心,其他定位判断assert等都是皮毛
 
8. basepage为什么要和test_case分开呢?
如果页面变了,不需要在test _case中修改代码
9. 显式等待
 
pasepage.py
wait_for 逻辑
#显式等待
 def wait_for(self, fun): # 如果fun返回了true,那么就退出显式等待 
       WebDriverWait(self._driver, 10).until(fun)
wait逻辑
def wait(driver): ele_len = len(self.finds(By.ID, "username")) if ele_len < 1: self.find(By.CSS_SELECTOR, ".js_has_member>div:nth-child(1) .js_add_member").click() # 如果username存在,就返回true return ele_len >= 1

坑2:wait(x)中一定要加上参数x,尽管没有被使用,因为until调用waitr()的时候把self.driver传给了wait()中的x参数(之前介绍显示等待中有讲到,给忘了。。。)

until源码: 源码:死循环,直到返回true或者返回超时,退出循环,如下图所示:

我们也可以不用自己定义wait函数,而是用selenium自带的 也可以用expected_condition方法,但是 也可以自己写,selenium自带的函数是不可以这么实现显式等待的,而自己写可以定制,想怎么写就怎么写,可以参考expected_condition源码方法
企业微信中的定位元素小总结:
1.
因为是要断言添加某个成员是否成功,这个页面又是动态增加的,因此就不能直接定位, 逻辑:取出所有成员,如果在这里就返回true,不在这里就返回false
方法一:td属于其父元素的第二个元素,先定位,因为有id,而td的父元素是tr,注意不是tbody(注意⚠️❗️重要重要!)
$('#member_list td:nth-child(2)’) 可以定位到所有tbody中的孙子元素,即所有tr中的第二个子元素就是name(姓名) 
处理逻辑如下:
2.
定位添加成员
<a class="qui_btn ww_btn js_add_member" href="javascript:;">添加成员</a>
class中空格的意思是有多个属性 ,这里有3个属性:qui_btn、ww_btn、 js_add_member,取其中一个就行
 

 

方法二:如果用class,定位到3个属性,其中有一个我们要的属性,那么我们往上找,找到他的父元素或者再网上,然后,它的第1 、2、3个属性就是我们想要的元素

 代码实现中踩过的一些坑 
 1.assert的对象要注意
 #只运行这部分不要加assert判断,否则会报错
def test_member(self):
       add_memeber = self.main.go_to_addmember()
       add_memeber.addmember() 
 报错如下:是因为上面的代码并不是返回的True或者False,assert是判断的bool值
2. 参考坑2
3.elen = len(self.finds(By.ID, 'username')),finds中封装的find_elements方法,为什么这里不用find_element因为它返回的是一个对象,而find_elements返回的是一个列表,才可以用len()方法
4.self.main = Main(reuse=True) #如果这里不传reuse=True将会开启一个新的浏览器
5.一个低级错误,return写在了里层
    def get_first_member(self):
        eles = self.finds(By.CSS_SELECTOR, '#member_list td:nth-child(2)')  # 元素定位
        arrs = []
        for ele in eles:
            arrs.append(ele.get_attribute("title"))
        return arrs  # 注意return要写在外层才是输出整个列表 
 6. 有时候报错有可能不是没有定位到元素,而是时间太快,页面没有加载出来还有忘记加click了,或者返回值没有其他方法来接收。。。
posted @ 2020-04-09 20:31  zhaikunkun  阅读(317)  评论(0)    收藏  举报