只有午安 发表于 2021-8-12 10:35

Python+selenium UI自动化一个小模式

本帖最后由 只有午安 于 2021-8-12 10:46 编辑

来了这么久,看了很多帖子,都没有发现有UI自动化这个东西,本人测试行业,最近也自己在学习这个东西,就发出来到目前写的一起学习一下吧,最好有大佬提供一下框架的思路。
这个是模式是我在网上找的一个叫PO模式(Page Objects),找了很多,个人觉得这个模式还可以。有不对的地方请大佬指正。{:301_993:}

PO模式介绍
用官话说它是selenium中的一种页面对象设计模式(不是测试框架!是一种开展ui自动化测试的思想),把ui自动化测试中的每个页面抽象出来,将每个页面用到的业务逻辑(page类)和页面元素(locator类)各自封装起来,然后编写测试用例时只需要调用每个page中的业务逻辑方法即可。测试(用例)脚本不需要关注元素的定位情况,当元素位置发生变化时,只需修改对应页面元素的locator即可

    使用页面对象模式的好处:
(1)创建可跨多个测试用例共享的可重用代码(每个测试用例只需调用page类中封装好的业务逻辑(操作)即可)。
(2)减少重复代码的数量。(如向输入框输入信息、单击操作等)
(3)如果用户界面发生变化,修改脚本只需要在一个地方进行更改。


BasePage页 (基类页,封装各种操作方法)
# coding: utf-8

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException


class BasePage:
    """封装其他页面都会用到的方法"""
    base_url = '某宝链接'

    def __init__(self, driver):
      self.driver = driver# 构造函数全局统一Driver

    def open(self):
      """打开页面的方法"""
      self.driver.get(self.base_url)# 启动浏览器打开链接
      self.driver.maximize_window()# 最大化窗口

    def find_element(self, locator):
      """定位元素的方法"""
      try:
            element = WebDriverWait(self.driver, 15).until(EC.presence_of_element_located(locator))
            return element
      except NoSuchElementException:
            print('%s 页面无 %s 元素' % (self, locator))

    def switch_frame(self, locator):
      """切换frame"""
      return self.driver.swtich_to_frame(locator)   # 切换frame后面暂未用到- -

    def send_key(self, locator, value, clear_first=True):
      """输入方法"""
      try:
            if clear_first:
                self.find_element(locator).clear()          # 清空输入框
            self.find_element(locator).send_keys(value)   # 查找元素 send内容
      except AttributeError:
            print('%s 页面无 %s 元素' % (self, locator))

    def click(self, locator):
      """点击方法"""
      self.find_element(locator).click()

    def get_current_url(self):
      """获取当前页面URL"""
      return self.driver.current_url

    def get_current_title(self):
      """获取当前页面标题"""
      return self.driver.title

    def switch_window(self):
      """
      切换窗口
      直接选择倒数第一个窗口
      后续操作才会在新窗口继续执行
      """
      nw = self.driver.window_handles
      self.driver.switch_to.window(nw[-1])
      return nw



locators页面 (存放页面内的元素位置)
from selenium.webdriver.common.by import By


class Locators():
    """元素定位器
    元素位置改变
    这里改"""
    first_page_locators = {
      'tblogo': (By.XPATH, '//div[@class="logo"]//h1/a'),
      'search': (By.XPATH, '//*[@id="J_TSearchForm"]/div/button'),
      'writer': (By.ID, 'q'), # '//input[@aria-label="请输入搜索文字"]'
      'value' : "鸿星尔克"
    }


if __name__ == "__main__":
    t = Locators()
    print(t.first_page_locators['writer'])
    # print(t.first_page_locators['search'])

Page页 (需要操作业务的页面)
from papes.BasePage import BasePage
from locators.locators import Locators


# 此页面加操作
class Firstpage(BasePage):
    value = Locators.first_page_locators["value"]
    tblogo = Locators.first_page_locators['tblogo']
    search = Locators.first_page_locators['search']
    shuru = Locators.first_page_locators['writer']

    def logo_click(self):
      """点击logo"""
      self.click(self.tblogo)

    def send_some(self):
      """输入框输入"""
      self.send_key(self.shuru, self.value)

    def search_click(self):
      """点击搜索"""
      self.click(self.search)


if __name__ == "__main__":
    t = Locators()
    print(t.first_page_locators['writer'])



t01 页 (unittest页面,也就是用例页面,直接调用page页,看起来就不会太冗余)
import unittest
from time import sleep

from papes.Firstpage import Firstpage
from selenium import webdriver
from papes.BasePage import BasePage


class MyTestCase(unittest.TestCase):
    @classmethod
    def setUpClass(cls):    # 只运行一次
      print("开始测试")

    def setUp(self):      # 每运行一次用例前执行
      # 实例化类 以及 赋值,方便调用
      self.driver = webdriver.Chrome()
      self.url = BasePage.base_url
      self.page = Firstpage(self.driver)
      self.page.open()
      self.jilei = BasePage(self.driver)

    def test_1(self):       # 用例1
      """
      加点等待时间等待页面元素加载
      尽量少使用固定等待
      - -我图方便才用这么多sleep
      用多了会导致时间长点,影响效率
      """
      self.driver.implicitly_wait(15)
      sleep(3)
      self.page.logo_click()   # 调用Page页定义好的函数
      sleep(3)
      self.page.switch_window()      # 切换窗口
      print(self.driver.current_url)      # 打印当前URL
      sleep(3)
      self.page.send_some()      # 输入内容 :Send_keys:
      sleep(3)

    def tearDown(self):   # 每运行一次用例后执行
      sleep(2)
      self.driver.quit()# 退出浏览器


if __name__ == '__main__':
    unittest.main()

Hangjau 发表于 2021-8-15 11:47

POM模式 这个设计的中心思想就是页面即对象。框架的话 也简单的   楼主其实已经实现了 整体框架 分为base、page、data、case、report   外加上ddt 和HTMLTestRunner 输出报告base 做为底层所有的动作,page将定位和操作步骤分开,data 测试数据的存储。 case 具体的页面用例。 report执行结果报告。
另外UI自动化成本太大。还是接口的比较实用。另外这个有个弊端就是一旦项目很大的情况下 整体的自动化项目会很臃肿因为页面变多了。每一个新页面就要写一个page文件,写一个case 文件。代码量还是偏高的。

zhangxu121213 发表于 2022-1-7 10:56

Hangjau 发表于 2022-1-6 22:34
只做冒烟的话 还真不一定覆盖页面所有点击。冒烟是根据业务主流程走的,不用考虑页面其他控件。注意的话 ...

感谢您,我试试,我是第一次写ui自动化,领导并没有给出需要测试的项,按我的理解

这个系统主要作为查询使用,不同类型查询,例如,警告,黑名单,白名单。而且每一个查询的页面都是iframe,每次点击查询,都要进入和退出,并且查询项涉及到各种条件,例如时间、模糊查询、类型、型号。查询的结果是列表形式展示在页面,我之前的想法是点击一次查询(不添加任何条件)。然后判断返回的列表信息。
您看,我是不是走错了方向,
是否有更简单的方式?

只有午安 发表于 2021-8-12 10:38

本帖最后由 只有午安 于 2021-8-12 11:06 编辑

妥了,原来不能分页= =

SagJoker 发表于 2021-8-12 10:52

额。我好像平时也是这样做。

huajt2004 发表于 2021-8-12 12:24

谢谢分享啊

orb001 发表于 2021-8-12 12:59

谢谢分享

syy 发表于 2021-8-13 09:47

那个啥 这种帖子可以描述的更普遍化一点 就是几乎到手把手给你解释那张 看的人懂了 就给评分了

只有午安 发表于 2021-8-13 10:39

syy 发表于 2021-8-13 09:47
那个啥 这种帖子可以描述的更普遍化一点 就是几乎到手把手给你解释那张 看的人懂了 就给评分了

代码里该注释的都注释了,好像没啥解释的了。。。{:301_979:}可能我就这拉跨水平吧

Bimice 发表于 2021-8-13 13:32

过来捧个场,,有所帮助{:301_978:}

helian147 发表于 2021-8-14 09:23

很好的通用模板,将方法,元素定位+取值都封装好了,最后直接调用即可,稍微改改具体的值就是能用爬虫,挺适用于js头大的大站
页: [1] 2 3
查看完整版本: Python+selenium UI自动化一个小模式