• app自动化06


    PO模式

    Page Object Model

    测试页面和测试脚本分离,即页面封装成类,供测试脚本进行调用。
    也就是说,脚本只需要负责关心流程,具体操作某个元素的步骤封装在页面对应的类的方法中

    优缺点

    优点
    1.提高测试用例的可读性;
    2.减少了代码的重复;
    3.提高测试用例的可维护性,特别是针对UI频繁变动的项目;
    缺点
    结构复杂: 基于流程做了模块化的拆分。

    项目需求

    - 更多-移动网络-首选网络类型-点击2G
    - 更多-移动网络-首选网络类型-点击3G
    - 显示-搜索按钮-输入hello-点击返回

    文件目录

    PO模式
    - scripts
    - - test_settting.py
    - pytest.ini

    代码

    test_setting.py
    import time
    from appium import webdriver
    
    
    class TestSetting:
    
        def setup(self):
            # server 启动参数
            desired_caps = {}
            # 设备信息
            desired_caps['platformName'] = 'Android'
            desired_caps['platformVersion'] = '5.1'
            desired_caps['deviceName'] = '192.168.56.101:5555'
            # app的信息
            desired_caps['appPackage'] = 'com.android.settings'
            desired_caps['appActivity'] = '.Settings'
            # 解决输入中文
            desired_caps['unicodeKeyboard'] = True
            desired_caps['resetKeyboard'] = True
    
            # 声明我们的driver对象
            self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    
        def test_mobile_network_2g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'2G')]").click()
    
        def test_mobile_network_3g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'3G')]").click()
    
        def test_mobile_display_input(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'显示')]").click()
            self.driver.find_element_by_id("com.android.settings:id/search").click()
            self.driver.find_element_by_id("android:id/search_src_text").send_keys("hello")
            self.driver.find_element_by_class_name("android.widget.ImageButton").click()
    
        def teardown(self):
            self.driver.quit()
    pytest.ini
    [pytest]
    # 添加行参数
    addopts = -s --html=./report/report.html
    # 文件搜索路径
    testpaths = ./scripts
    # 文件名称
    python_files = test_*.py
    # 类名称
    python_classes = Test*
    # 方法名称
    python_functions = test_*

    多文件区分测试用例

    需求

    - 使用多个文件来区分不同的测试页面

    好处

    -修改不同的功能找对应的文件即可

    步骤

    1. 在scripts下新建test_network.py文件
    2. 在scripts下新建test_dispaly.py文件
    3. 移动不同的功能代码到对应的文件
    4. 移除原有的test_setting.py文件

    文件目录

    PO模式
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    test_network.py
    from appium import webdriver
    
    
    class TestNetwork:
    
        def setup(self):
            # server 启动参数
            desired_caps = {}
            # 设备信息
            desired_caps['platformName'] = 'Android'
            desired_caps['platformVersion'] = '5.1'
            desired_caps['deviceName'] = '192.168.56.101:5555'
            # app的信息
            desired_caps['appPackage'] = 'com.android.settings'
            desired_caps['appActivity'] = '.Settings'
            # 解决输入中文
            desired_caps['unicodeKeyboard'] = True
            desired_caps['resetKeyboard'] = True
    
            # 声明我们的driver对象
            self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    
        def test_mobile_network_2g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'2G')]").click()
    
        def test_mobile_network_3g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'3G')]").click()
    
        def teardown(self):
            self.driver.quit()
    test_display.py
    from appium import webdriver
    
    
    class TestDisplay:
    
        def setup(self):
            # server 启动参数
            desired_caps = {}
            # 设备信息
            desired_caps['platformName'] = 'Android'
            desired_caps['platformVersion'] = '5.1'
            desired_caps['deviceName'] = '192.168.56.101:5555'
            # app的信息
            desired_caps['appPackage'] = 'com.android.settings'
            desired_caps['appActivity'] = '.Settings'
            # 解决输入中文
            desired_caps['unicodeKeyboard'] = True
            desired_caps['resetKeyboard'] = True
    
            # 声明我们的driver对象
            self.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    
        def test_mobile_display_input(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'显示')]").click()
            self.driver.find_element_by_id("com.android.settings:id/search").click()
            self.driver.find_element_by_id("android:id/search_src_text").send_keys("hello")
            self.driver.find_element_by_class_name("android.widget.ImageButton").click()
    
        def teardown(self):
            self.driver.quit()
    

    封装前置代码

    需求

    - 将前置代码进行封装

    好处

    - 前置代码只需要写一份

    步骤

    1. 新建base文件夹
    2. 新建base_driver.py文件
    3. 新建函数init_driver
    4. 写入前置代码并返回
    5. 修改测试文件中的代码

    文件目录

    PO模式
    - base
    - - base_driver.py
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    base_driver.py
    from appium import webdriver
    
    def init_driver():
        # server 启动参数
        desired_caps = {}
        # 设备信息
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '5.1'
        desired_caps['deviceName'] = '192.168.56.101:5555'
        # app的信息
        desired_caps['appPackage'] = 'com.android.settings'
        desired_caps['appActivity'] = '.Settings'
        # 解决输入中文
        desired_caps['unicodeKeyboard'] = True
        desired_caps['resetKeyboard'] = True
        # 声明我们的driver对象
        return webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    test_network.py
    from base.base_driver import init_driver
    
    
    class TestNetwork:
    
        def setup(self):
            self.driver = init_driver()
    
        def test_mobile_network_2g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'2G')]").click()
    
        def test_mobile_network_3g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'3G')]").click()
    
        def teardown(self):
            self.driver.quit()
    test_display.py
    from base.base_driver import init_driver
    
    
    class TestDisplay:
    
        def setup(self):
            self.driver = init_driver()
    
        def test_mobile_display_input(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'显示')]").click()
            self.driver.find_element_by_id("com.android.settings:id/search").click()
            self.driver.find_element_by_id("android:id/search_src_text").send_keys("hello")
            self.driver.find_element_by_class_name("android.widget.ImageButton").click()
    
        def teardown(self):
            self.driver.quit()

    分离测试脚本

    需求

    • 测试脚本只剩流程
    • 其他的步骤放倒page类中

    好处

    • 测试脚本只专注过程
    • 过程改变只需要修改脚本
    • 增加可维护性

    步骤

    1. 新建page文件夹
    2. 新建network_page.py文件
    3. 新建display_page.py文件
    4. 调用init函数传入driver
    5. init进入需要测试的页面
    6. page中新建“小动作”函数
    7. 移动代码
    8. 修改测试文件中的代码

    文件目录

    PO模式
    - base
    - - base_driver.py
    - page
    - - network_page.py
    - - display_page.py
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    base_driver.py
    from appium import webdriver
    
    def init_driver():
        # server 启动参数
        desired_caps = {}
        # 设备信息
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '5.1'
        desired_caps['deviceName'] = '192.168.56.101:5555'
        # app的信息
        desired_caps['appPackage'] = 'com.android.settings'
        desired_caps['appActivity'] = '.Settings'
        # 解决输入中文
        desired_caps['unicodeKeyboard'] = True
        desired_caps['resetKeyboard'] = True
    
        # 声明我们的driver对象
        return webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    network_page.py
    class NetWorkPage:
    
        def __init__(self, driver):
            self.driver = driver
            self.driver.find_element_by_xpath("//*[contains(@text,'更多')]").click()
            self.driver.find_element_by_xpath("//*[contains(@text,'移动网络')]").click()
    
        def click_first_network(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'首选网络类型')]").click()
    
        def click_2g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'2G')]").click()
            
        def click_3g(self):
            self.driver.find_element_by_xpath("//*[contains(@text,'3G')]").click()
    display_page.py
    class DisplayPage:
    
        def __init__(self, driver):
            self.driver = driver
            self.driver.find_element_by_xpath("//*[contains(@text,'显示')]").click()
    
        def click_search(self):
            self.driver.find_element_by_id("com.android.settings:id/search").click()
    
        def input_text(self, text):
            self.driver.find_element_by_id("android:id/search_src_text").send_keys(text)
    
        def click_back(self):
            self.driver.find_element_by_class_name("android.widget.ImageButton").click()
    test_network.py
    import sys, os
    sys.path.append(os.getcwd())
    
    from base.base_driver import init_driver
    from page.network_page import NetWorkPage
    
    
    class TestNetwork:
    
        def setup(self):
            self.driver = init_driver()
            self.network_page = NetWorkPage(self.driver)
    
        def test_mobile_network_2g(self):
            self.network_page.click_first_network()
            self.network_page.click_2g()
    
        def test_mobile_network_3g(self):
            self.network_page.click_first_network()
            self.network_page.click_3g()
    
        def teardown(self):
            self.driver.quit()
    test_display.py
    import sys, os
    sys.path.append(os.getcwd())
    
    
    from base.base_driver import init_driver
    from page.display_page import DisplayPage
    
    
    class TestDisplay:
    
        def setup(self):
            self.driver = init_driver()
            self.display_page = DisplayPage(self.driver)
    
        def test_mobile_display_input(self):
            self.display_page.click_search()
            self.display_page.input_text("hello")
            self.display_page.click_back()
    
        def teardown(self):
            self.driver.quit()

    抽取查找元素的特征

    需求

    - 将元素的特征放在函数之上

    好处

    - 若特征改了,流程不变,可以直接在上面修改

    步骤

    1. 将find_element_by_xxx改为find_element
    2. 将方式和具体特征向上移动
    一切目的都是为了代码简单易于维护。

    文件目录

    PO模式
    - base
    - - base_driver.py
    - page
    - - network_page.py
    - - display_page.py
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    base_driver.py
    from appium import webdriver
    
    def init_driver():
        # server 启动参数
        desired_caps = {}
        # 设备信息
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '5.1'
        desired_caps['deviceName'] = '192.168.56.101:5555'
        # app的信息
        desired_caps['appPackage'] = 'com.android.settings'
        desired_caps['appActivity'] = '.Settings'
        # 解决输入中文
        desired_caps['unicodeKeyboard'] = True
        desired_caps['resetKeyboard'] = True
    
        # 声明我们的driver对象
        return webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    network_page.py
    from selenium.webdriver.common.by import By
    
    
    class NetWorkPage:
    
        more_button = By.XPATH, "//*[contains(@text,'更多')]"   // 元组类型
        mobile_network_button = By.XPATH, "//*[contains(@text,'移动网络')]"
        click_first_network_button = By.XPATH, "//*[contains(@text,'首选网络类型')]"
        network_2g_button = By.XPATH, "//*[contains(@text,'2G')]"
        network_3g_button = By.XPATH, "//*[contains(@text,'3G')]"
    
        def __init__(self, driver):
            self.driver = driver
            self.driver.find_element(self.more_button).click()
            self.driver.find_element(self.mobile_network_button).click()
    
        def click_first_network(self):
            self.driver.find_element(self.click_first_network_button).click()
    
        def click_2g(self):
            self.driver.find_element(self.network_2g_button).click()
    
        def click_3g(self):
            self.driver.find_element(self.network_3g_button).click()
    display_page.py
    from selenium.webdriver.common.by import By
    
    
    class DisplayPage:
    
        display_button = By.XPATH, "//*[contains(@text,'显示')]"   // 元组
        search_button = By.ID, "com.android.settings:id/search"
        search_edit_text = By.ID, "android:id/search_src_text"
        back_button = By.CLASS_NAME, "android.widget.ImageButton"
    
        def __init__(self, driver):
            self.driver = driver
            self.driver.find_element(self.display_button).click()
    
        def click_search(self):
            self.driver.find_element(self.search_button).click()
    
        def input_text(self, text):
            self.driver.find_element(self.search_edit_text).send_keys(text)
    
        def click_back(self):
            self.driver.find_element(self.back_button).click()
    test_network.py
    import sys, os
    sys.path.append(os.getcwd())
    
    from base.base_driver import init_driver
    from page.network_page import NetWorkPage
    
    
    class TestNetwork:
    
        def setup(self):
            self.driver = init_driver()
            self.network_page = NetWorkPage(self.driver)
    
        def test_mobile_network_2g(self):
            self.network_page.click_first_network()
            self.network_page.click_2g()
    
        def test_mobile_network_3g(self):
            self.network_page.click_first_network()
            self.network_page.click_3g()
    
        def teardown(self):
            self.driver.quit()
    test_display.py
    import sys, os
    sys.path.append(os.getcwd())
    
    
    from base.base_driver import init_driver
    from page.display_page import DisplayPage
    
    
    class TestDisplay:
    
        def setup(self):
            self.driver = init_driver()
            self.display_page = DisplayPage(self.driver)
    
        def test_mobile_display_input(self):
            self.display_page.click_search()
            self.display_page.input_text("hello")
            self.display_page.click_back()
    
        def teardown(self):
            self.driver.quit()

    抽取action

    需求

    - 将动作进行封装

    步骤

    1. 新建base_action.py文件
    2. 将click、send_keys抽取到文件中

    文件目录

    PO模式
    - base
    - - base_driver.py
    - - base_action.py
    - page
    - - network_page.py
    - - display_page.py
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    base_action.py
    class BaseAction:
    
        def __init__(self, driver):
            self.driver = driver
    
        def click(self, loc):
            self.driver.find_element(loc[0], loc[1]).click()
    
        def input(self, loc, text):
            self.driver.find_element(loc[0], loc[1]).send_keys(text)
    network_page.py
    import sys, os
    sys.path.append(os.getcwd())
    
    from selenium.webdriver.common.by import By
    from base.base_action import BaseAction
    
    
    class NetWorkPage(BaseAction):
    
        more_button = By.XPATH, "//*[contains(@text,'更多')]"
        mobile_network_button = By.XPATH, "//*[contains(@text,'移动网络')]"
        click_first_network_button = By.XPATH, "//*[contains(@text,'首选网络类型')]"
        network_2g_button = By.XPATH, "//*[contains(@text,'2G')]"
        network_3g_button = By.XPATH, "//*[contains(@text,'3G')]"
    
        def __init__(self, driver):
            BaseAction.__init__(self, driver)
            self.click(self.more_button)
            self.click(self.mobile_network_button)
    
        def click_first_network(self):
            self.click(self.click_first_network_button)
    
        def click_2g(self):
            self.click(self.network_2g_button)
    
        def click_3g(self):
            self.click(self.network_3g_button)
    display_page.py
    import sys, os
    sys.path.append(os.getcwd())
    
    from selenium.webdriver.common.by import By
    from base.base_action import BaseAction
    class DisplayPage(BaseAction):
    
        display_button = By.XPATH, "//*[contains(@text,'显示')]"
        search_button = By.ID, "com.android.settings:id/search"
        search_edit_text = By.ID, "android:id/search_src_text"
        back_button = By.CLASS_NAME, "android.widget.ImageButton"
    
        def __init__(self, driver):
            BaseAction.__init__(self, driver)
            self.click(self.display_button)
    
        def click_search(self):
            self.click(self.search_button)
    
        def input_text(self, text):
            self.input(self.search_edit_text, text)
    
        def click_back(self):
            self.click(self.back_button)
    test_network.py
    import sys, os
    sys.path.append(os.getcwd())
    
    from base.base_driver import init_driver
    from page.network_page import NetWorkPage
    class TestNetwork:
        def setup(self):
            self.driver = init_driver()
            self.network_page = NetWorkPage(self.driver)
    
        def test_mobile_network_2g(self):
            self.network_page.click_first_network()
            self.network_page.click_2g()
    
        def test_mobile_network_3g(self):
            self.network_page.click_first_network()
            self.network_page.click_3g()
    
        def teardown(self):
            self.driver.quit()
    test_display.py
    import sys, os
    
    import time
    
    sys.path.append(os.getcwd())
    
    from base.base_driver import init_driver
    from page.display_page import DisplayPage
    
    
    class TestDisplay:
        def setup(self):
            self.driver = init_driver()
            self.display_page = DisplayPage(self.driver)
    
        def test_mobile_display_input(self):
            self.display_page.click_search()
            self.display_page.input_text("hello")
            self.display_page.click_back()
        def teardown(self):
            self.driver.quit()

    增加WebDriverWait

    需求

    - 找控件使用WebDriverWait

    好处

    - 防止出现cpu卡的时候找不到

    步骤

    1. 自己新建find方法
    2. 在系统的基础上增加WebDriverWait
    文件目录
    PO模式
    - base
    - - base_driver.py
    - - base_action.py
    - page
    - - network_page.py
    - - display_page.py
    - scripts
    - - test_network.py
    - - test_dispaly.py
    - pytest.ini

    代码

    base_action.py
    from selenium.webdriver.support.wait import WebDriverWait
    
    
    class BaseAction:
    
        def __init__(self, driver):
            self.driver = driver
    
        def find_element(self, loc, time=10, poll=1):
            return WebDriverWait(self.driver, time, poll).until(lambda x: x.find_element(loc[0], loc[1]))
            # return self.driver.find_element(by, value)
    
        def find_elements(self, loc, time=10, poll=1):
            return WebDriverWait(self.driver, time, poll).until(lambda x: x.find_elements(loc[0], loc[1]))
            # return self.driver.find_elements(by, value)
    
        def click(self, loc):
            self.find_element(loc).click()
    
        def input(self, loc, text):
            self.find_element(loc).send_keys(text)

    总结图:



  • 相关阅读:
    JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、jinfo、jconsole使用详解
    Spark入Hbase的四种方式效率对比
    redis的三种集群方式
    记Springcloud Config Service整合gitlab一坑
    移动开发day2_css预处理器_flex布局
    移动开发day1_过渡_2d转换_3d立体
    3月26-3月27号
    3月24号
    3月25号
    3月23日
  • 原文地址:https://www.cnblogs.com/st998/p/13804230.html
Copyright © 2020-2023  润新知