• selenium +python之Page Obiect设计模式


    PageObject是selenium自动化测试项目开发实践的最佳设计模式之一,它主要体现对界面交互细节的封装,这样可以使测试案例更关注于业务而非界面细节,从而提高测试案例的可读性。

    1.认识PageObject

    PageObject设计模式的优点如下:

    *减少代码的重复

    *提高测试用例的可读性

    *提高测试用例的可维护性,特别针对UI频繁变动的项目。

    当为web页面编写测试是,需要操作该web页面上的元素。然而,如果在测试代码中直接操作HTML元素,代码是及其脆弱的,因为ui的变动性会很大。我们可以将page对象封装成一个HTML页面,然后通过提供应用程序特定的API来操作页面元素。而不是在HTML中来定位。

    page对象的一个基本经验法则是:凡是人能够做的事,page对象通过软件客户端都能够做到。因此,他应该提供一个易于编程的接口并隐藏窗口底层的部件。所以访问一个文本框应该通过一个访问方法(accessor method)来实现字符串的获取与返回,复选框应当使用布尔值,按钮应当被表示为行为导向的方法名。page对象应当将在GUI控件上所有查询和操作数据的行为封装为方法

    一个好的经验法则是:即使改变具体的控件,page对象的接口也不应当发生改变

    尽管该术语是:“页面”对象,但是并不意味着需要针对每个页面建立一个这样的对象。例如:页面有重要意义的元素可以独立为一个page对象。经验法则的目的是通过给页面建模,时期对应用程序的使用者变得更有意义。

     1 from selenium import webdriver
     2 from selenium.webdriver.common.by import By
     3 from time import sleep
     4 
     5 
     6 class Page(object):
     7     """
     8     基础类,用于页面对象类的继承
     9     """
    10     login_url = 'http://mail.163.com/'
    11 
    12     def __init__(self, selenium_driver, base_url=login_url):
    13         self.base_url = base_url
    14         self.driver = selenium_driver
    15         self.timeout = 30
    16 
    17     def on_page(self):
    18         return self.driver.current_url == (self.base_url + self.url)
    19 
    20     def _open(self, url):
    21         url = self.base_url + url
    22         self.driver.get(url)
    23         assert self.on_page(), 'Did not land on %s' % url
    24 
    25     def open(self):
    26         self._open(self.url)
    27 
    28     def find_element(self, *loc):
    29         return self.driver.find_element(*loc)
    30 
    31 
    32 class LoginPage(Page):
    33     """
    34     126邮箱登陆页面模型
    35     """
    36     url = '/'
    37     # 定位器
    38     username_loc = (By.ID, "idInput")
    39     password_loc = (By.ID, "pwdInput")
    40     submit_loc = (By.ID, "loginBtn")
    41 
    42     # Action
    43     def type_username(self, username):
    44         self.find_element(*self.username_loc).send_keys(username)
    45 
    46     def type_password(self, password):
    47         self.find_element(*self.password_loc).send_keys(password)
    48 
    49     def submit(self):
    50         self.find_element(*self.submit_loc).click()
    51 
    52 
    53 def test_user_login(driver, username, password):
    54     """
    55      测试获取的用户名/密码是否可以登陆
    56      """
    57     login_page = LoginPage(driver)
    58     login_page.open()
    59     login_page.type_username(username)
    60     login_page.type_password(password)
    61     login_page.submit()
    62 
    63 
    64 def main():
    65     try:
    66         driver = webdriver.Chrome()
    67         username = 'fengyiru6369@163.com'
    68         password = '********'
    69         test_user_login(driver, username, password)
    70         sleep(3)
    71         text = driver.find_element_by_xpath("//span[@id = 'spnUid']").text
    72         assert (text == 'fengyiru6369@163.com'), "用户名称不匹配,登陆失败!"
    73     finally:
    74         # 关闭浏览器窗口
    75         driver.close()
    76 
    77 
    78 if __name__ == '__main__':
    79     main()

     代码解释如下:

    1、创建page类

     1 class Page(object):
     2     """
     3     基础类,用于页面对象类的继承
     4     """
     5     login_url = 'http://mail.163.com/'
     6 
     7     def __init__(self, selenium_driver, base_url=login_url):
     8         self.base_url = base_url
     9         self.driver = selenium_driver
    10         self.timeout = 30
    11 
    12     def on_page(self):
    13         return self.driver.current_url == (self.base_url + self.url)
    14 
    15     def _open(self, url):
    16         url = self.base_url + url
    17         self.driver.get(url)
    18         assert self.on_page(), 'Did not land on %s' % url
    19 
    20     def open(self):
    21         self._open(self.url)
    22 
    23     def find_element(self, *loc):
    24         return self.driver.find_element(*loc)
    首先创建一个基础类Page,在初始化方法__init__()中定义驱动(driver),基本的URL(base_url)和超时时间(timeout)等,定义open()方法用于打开URL网站,但是它本身并未做这件事情,而是交由
    _open()方法来实现。关于Url地址的断言部分,则交由on_page()方法来实现,而find_element()方法用于元素的定位。

    2.创建LoginPage类

    Page类中定义的这些方法都是页面操作的基本方法。下面根据登陆页的特点再创建LoginPage类并继承page类,这也是page object设计模式中最重要的对象层。

     1 class LoginPage(Page):
     2     """
     3     126邮箱登陆页面模型
     4     """
     5     url = '/'
     6     # 定位器
     7     username_loc = (By.ID, "idInput")
     8     password_loc = (By.ID, "pwdInput")
     9     submit_loc = (By.ID, "loginBtn")
    10 
    11     # Action
    12     def type_username(self, username):
    13         self.find_element(*self.username_loc).send_keys(username)
    14 
    15     def type_password(self, password):
    16         self.find_element(*self.password_loc).send_keys(password)
    17 
    18     def submit(self):
    19         self.find_element(*self.submit_loc).click()
    LoginPage类中主要对登陆页面上的元素进行封装,使其成为更具体的操作方法。例如,用户名,密码和登陆按钮都被封装成了方法。

    3.创建test_user_login()函数

    1 def test_user_login(driver, username, password):
    2     """
    3      测试获取的用户名/密码是否可以登陆
    4      """
    5     login_page = LoginPage(driver)
    6     login_page.open()
    7     login_page.type_username(username)
    8     login_page.type_password(password)
    9     login_page.submit()

    test_user_login()函数将单个的元素操作组成一个完整的动作,而这个动作包含了打开浏览器,输入用户名/密码,点击登陆等单步操作。在使用该函数时需要将driver,username、password等信息作为函数的入参,这样该函数具有很强的可重用性。

    4.创建main()函数

     1 def main():
     2     try:
     3         driver = webdriver.Chrome()
     4         username = 'fengyiru6369@163.com'
     5         password = '********'
     6         test_user_login(driver, username, password)
     7         sleep(3)
     8         text = driver.find_element_by_xpath("//span[@id = 'spnUid']").text
     9         assert (text == 'fengyiru6369@163.com'), "用户名称不匹配,登陆失败!"
    10     finally:
    11         # 关闭浏览器窗口
    12         driver.close()
    13 
    14 
    15 if __name__ == '__main__':
    16     main()

    main()函数更接近于用户的操作行为,对用户来说,要进行邮箱登陆,需要关心的就是通过哪个浏览器打开邮箱网址,登陆的用户名和密码是什么,至于输入框,按钮时如何定位的,则不需要关心。

    这样分层的好处是,不同的层关心不同的问题。页面对象层只关心元素定位的问题,测试用例只关心测试数据。

    一个有分歧的地方是page对象是否应自身包含断言,或者仅仅提供数据给测试脚本来设置断言。在page对象中包含断言的倡导者认为,这又助于避免在测试脚本中出现重复的断言,可以更容易的提供更好的错误信息,并且提供更接近只做不问风格的API。不在page对象中包含断言的倡导者认为,包含断言会混合访问页面数据和实现断言逻辑的职责,并且导致page对象过于臃肿。

    在page对象中不包含断言,虽然我们可以通过为常用的断言提供断言库的方式来消除重复,提供更好的诊断,但从用户的角度去自动化的观点来看,判断是否登陆成功是用户需要做的事情,不该交由页面对象层来完成。

    使用page object模式之后的另外一个好处就是有助于降低冗余。如果需要在10个用例中输入不同的用户名/密码登陆,那么main()方法竟会变得非常简洁。

  • 相关阅读:
    C# Socket编程
    C# Socket编程
    Android基础入门教程
    Android基础入门教程
    SQL Server查询事务
    SQL Server查询事务
    SQL事务用法begin tran,commit tran和rollback tran的用法
    SQL事务用法begin tran,commit tran和rollback tran的用法
    SQL Server Insert操作中的锁
    SQL Server Insert操作中的锁
  • 原文地址:https://www.cnblogs.com/fengyiru6369/p/7859500.html
Copyright © 2020-2023  润新知