Design pattern based on Python+Selenium+Unittest+PO

1. What is the PO design pattern (Page Object Model)

1. Page Object is a design pattern, which is mainly reflected in the encapsulation of interface interaction details, making test cases more focused on business operations, thereby improving the maintainability of test cases.

2. The general PO design pattern has three layers

level one:

  • Secondary encapsulation of Selenium, defining a BasePage that all pages inherit,
  • Encapsulates basic methods of Selenium such as: element positioning, element waiting, navigating pages,
  • There is no need to encapsulate all of them, as many methods as are used.

Second floor:

  • The page elements are separated, and each element is only positioned once, and the positioning is isolated. If the page changes, only the corresponding element positioning needs to be changed;
  • Business logic separation or operation element action separation

the third floor:

  • Test business logic using a unit testing framework

 2. Why use the PO design pattern

  • Frequent changes in the page, (changes in the html structure of the page, etc.) lead to frequent changes in the UI elements of the page, and changes in element positioning
  • Traditional linear automation (process-oriented development), use cases need to repeatedly locate the same element
  • Whenever the page changes, it is necessary to find the changed part in the use case, the workload is heavy, it is easy to omit, and it is not easy to maintain

3. Six principles of PO design pattern

  • Public methods represent services provided by the page
  • don't reveal details
  • Don't make assertions in encapsulated frames
  • The method can return to the newly opened page
  • Don't model everything, only the ones you care about
  • Same behavior produces different results, different results can be encapsulated

4. Example of PO design pattern

Take the company's unified login as a project example, and use the PO design pattern to achieve login:

1. Manual use case:

use case number title Preconditions Steps expected outcome actual results
T-001 login successful Enter the correct username and password

1. Open the unified login page

2. Enter the user name

3. Enter the password

4. Click the login button

The login is successful, and the correct jump to the application system interface XXX
T-002 Login failed wrong username

1. Open the unified login page

2. Enter the user name

3. Enter the password

4. Click the login button

Login failed, correct prompt username or password is incorrect XXX

2. Use PO mode to realize automation use cases

project directory

Base.py

login_page.py

from Page import Base

# 创建LoginPage类继续BasePage类
class LoginPage(Base.BasePage):
    '''统一平台登录Page层,登录页面封装操作到的元素'''
    '''第二层:页面元素进行分离,每个元素只定位一次,操作元素动作分离'''
    # 定义url变量,供父类中的open()方法使用
    url ="https://test01....cn/#/login"
    # 用户名输入框定位
    def form_username(self,user_name):
        return self.by_id("name").send_keys(user_name) # 使用了父类的self.by_id()方法定位元素,简洁了不少
    # 密码输入框定位
    def form_password(self,pass_word):
        return self.by_id("password").send_keys(pass_word)
    # 登录按钮定位
    def button_login(self):
        return self.by_xpath("//*[text()='登录']").click()

test_login.py

from Page import login_page
import unittest
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.keys import Keys
from CommonMethod import LogUtil

logger = LogUtil.logs() # 调用封装的日志方法,将日志输出到控制台以及写入文件

class LoginCase(unittest.TestCase):
    '''第三层:用单元测试框架对业务逻辑进行测试'''
    '''使用LoginPage类及它所继承的父类中的方法'''
    @classmethod
    def setUpClass(cls):
        # 实例化webdriver,俗称:打开浏览器
        cls.driver = webdriver.Firefox(executable_path='E:\\UI test\\UnittestProject\\Driver\\geckodriver.exe')
        cls.driver.implicitly_wait(10)
    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()
    def test_login_success(self):
        page = login_page.LoginPage(self.driver) # 需要用到哪个Page类时,只需要将它传入浏览器驱动,就可以使用该类中提供的方法了
        page.open()
        page.form_username("XXX")
        page.form_password("123456")
        page.button_login()
        sleep(2)
        self.assertEqual(page.get_current_url(), "https://test01....cn/#/home")
        print("登录成功,用例执行结果通过,当前的url为"+ page.get_current_url())
        sleep(1)
    def test_login_fail(self):
        page = login_page.LoginPage(self.driver)
        page.open()
        page.form_username("XXX11")
        page.form_password("123456")
        page.button_login()
        self.assertNotEqual(page.get_current_url(), "https://test01....cn/#/home")
        print("登录失败,用例执行结果通过,当前的url为"+ page.get_current_url())
        page.form_username(Keys.CONTROL+'a') # 输入组合键Ctrl+a,全选输入框内容
        page.form_username(Keys.BACK_SPACE) # 删除键,删除选中的内容
        page.form_password(Keys.CONTROL + 'a')
        page.form_password(Keys.BACK_SPACE)
        sleep(1)
if __name__ == '__main__':
    unittest.main(verbosity=2)

Results of the

In test_login.py, there is a call to the encapsulated log method. Here, the encapsulated log is attached. LogUtil.py in the CommonMethod directory

 LogUtil

 5. Other Supplements

1. The same behavior will produce different results, and different results can be encapsulated: 2 methods are encapsulated for the [Login] button on the login_page

2. The method can return to the newly opened page: encapsulate the [Login] button on the login_page, and return the new page or other information after encapsulation. Just name the variable to receive this function when test_login is called, such as indexurl = page.button_login_success(), and later assert that you can use the indexurl variable to assert with the expected url

 # 登录失败封装
    def button_login_fail(self):
        self.by_xpath("//span[text()='登录']").click()
        toast = self.by_xpath("//p[text()='账号或密码错误!']").text
        return toast

    # 登录成功封装
    def button_login_success(self):
        self.by_xpath("//span[text()='登录']").click()
        sleep(2)
        windows = self.driver.window_handles# 获取打开的多个窗口句柄
        self.driver.switch_to.window(windows[-1])# 切换到当前最新打开的窗口
        indexurl = self.get_current_url()
        return indexurl

3. Assertion: You can assert through url, page title, and text

'''断言跳转的地址,通过try except语句块来进行测试断言,在实际自动化测试脚本开发中,经常要用到处理异常'''
        try:
            self.assertEqual(indexurl,"https://qa-xxxt/add")
            print("点击创建,正确跳转到新页面" + indexurl)
        except AssertionError as msg:
            print("没有跳转到正确页面,当前跳转的地址为"+addurl+"\n报错信息如下"+format(msg))
            '''当断言失败时会抛出异常测试用例执行失败,输出提示信息后重新将异常抛出,即raise,
            若不重新抛出,用例则永远是显示执行成功的,因为它把异常处理掉了'''
            raise msg

  try:
            self.assertEqual(toast, "账号或密码错误!")
            print("登录失败用例场景执行通过,正确弹出提示信息为:" + toast)
        except AssertionError as msg:
            print("错误提示语与预期结果不一致,请检查"+ format(msg))
            raise msg

try:
            self.assertIn("2106000013",source) # 断言搜索值是否存在页面源码中
            print("正确搜索出该编号数据")
            excepttotal ="1"
            self.assertEqual(total,excepttotal) # 断言total值是否为1
            print("底部分页统计正确,搜索出"+total+"条数据")
        except AssertionError as msg:
            print("搜索的数据不正确"+format(msg))
            raise msg    

 Summarize:

Thanks to everyone who read my article carefully! ! !

I personally sorted out some technical materials I have compiled in my software testing career in the past few years, including: e-books, resume modules, various job templates, interview books, self-study projects, etc. Welcome everyone to click on the business card below to get it for free, don't miss it.

   Python automated testing learning exchange group: a full set of automated testing interview resume learning materials to obtain Click the link to join the group chat [python automated testing exchange]: http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DhOSZDNS-qzT5QKbFQMsfJ7DsrFfKpOF&authKey=eBt%2BF%2FBK81lVLcsLKaFqnvDAVA 8IdNsGC7J0YV73w8V%2FJpdby66r7vJ1rsPIifg&noverify=0&group_code=198408628

 

Guess you like

Origin blog.csdn.net/manbskjabgkb/article/details/131839575