【WebUIAuto】1.web端UI自动化

环境安装步骤

1.准备好python环境
2.准备selenium环境
3.下载浏览器对应版本的driver,点击下载chromedriver
4.driver配置环境变量
5.在python里导入对应依赖

selenium IDE 录制

seleniumIDE官网

点击进入扩展程序

selenium 用例编写

python-selenium文档
selenium常用等待

  • 直接等待
    time.sleep(3) 等待3秒
  • 隐式等待
    driver.implicitly_wait(5) 轮训查找(默认0.5)元素是否出现,如果没出现就抛出异常
  • 显示等待
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestWebUi:
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.get("http://www.baidu.com")
        # 隐式等待
        self.driver.implicitly_wait(5)
    def teardown(self):
        self.driver.close()

    def test_search(self):

        self.driver.find_element(By.ID,'kw').send_keys('腾讯课堂')
        self.driver.find_element(By.ID, 'su').click()
        self.driver.find_element(By.LINK_TEXT,'腾讯课堂【官方】_腾讯课堂【官方】腾讯课堂官网').click()
          #显示等待
        WebDriverWait(self.driver,10).until(expected_conditions.presence_of_all_elements_located((By.LINK_TEXT,'官方')))
        
web控件定位,操作
  • 操作
    输入: self.driver.find_element(By.ID,'kw').send_keys('腾讯课堂')
    点击: self.driver.find_element(By.ID, 'su').click()
  • 定位-xpath
    作用域(appium、selenim)
表达式 结果
/div/input[1] 取div子元素的第一个input元素
/div/input[last()] 取div子元素的最后个input元素
/div/input[last()-1] 取div子元素的倒数第二个input元素
/div/input[position()<3] 取div子元素的前两个book元素
//div[@class='classname'] 得到所有div元素,且这些元素拥有值为classaname的class属性
/div/input[price>35] 得到所有div元素下的所有input,且其中的price元素值大于35,且这些元素拥有值为classaname的class属性
nodename 选取此节点的所有子节点
/ 从根节点选取
// 匹配选择当前节点,不考虑其位置
. 选取当前节点
.. 选取当前节点父节点
@ 选取属性
  • 定位-css selector
    appium 原生元素不能用 css selector定位
表达式 结果 例子描述
.class .intro 选择 class = "intro"的所有元素
.id .idname 选择 id= "idname"的所有元素
* * 选择所有元素
element div 选择所有<div>元素
element,element div,p 选择所有<div>元素和所有<p>元素
element element div p 选择<div>元素内部的所有<p>元素
element>element div>p 选择父元素为<div>元素的所有<p>元素
element+element div+p 选择紧接在<div>元素之后的所有<p>元素
css select f方式
web控件交互

Actions

  • 官方文档
  • ActionChains:执行鼠标点击、双击、右键、拖拽事件
  • TouchActions: 模拟PC移动端、点击、滑动、拖拽、多点触控操作
  • 执行原理,调用actionChains方法,不会立即执行,而是讲所有的操作,按顺序放在一个队列里,调用perform()方法时,队列中的事件会依次执行
  • 基本用法
  1. 生成一个动作 action = ActionChains(driver)
  2. 动作添加方法1 action.方法1
  3. 调用perform()方法执行(action.perform())
  • 写法
  1. 链式写法 ActionChains(driver).move_to_element(element).click(element).perform()
  2. 分布写法
    action= ActionChains(driver)
    action.move_to_element(element)
    actions.click(element)
    actions.perform()

ActionChains示例

class TestActionChains():
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.get("http://sahitest.com/demo/clicks.htm")
        self.driver.implicitly_wait(5)

    def teardown(self):
        self.driver.close()

    def test_case_click(self):
        element_click = self.driver.find_element(By.XPATH,'//input[@value="click me"]')
        element_dbclick = self.driver.find_element(By.XPATH,'//input[@value="dbl click me"]')
        element_rclick = self.driver.find_element(By.XPATH,'//input[@value="right click me"]')
        action = ActionChains(self.driver)
        action.click(element_click)
        action.double_click(element_dbclick)# 双击操作
        action.context_click(element_rclick)# 右击操作
        action.perform()
        sleep(3)
    def test_move_to(self):
        # 光标移动到某个元素
        self.driver.get("http://www.baidu.com")
        element = self.driver.find_element(By.ID,'s-usersetting-top')
        action = ActionChains(self.driver)
        action.move_to_element(element)
        action.perform()
        sleep(2)
    def test_dragdrog(self):
        self.driver.get("http://sahitest.com/demo/dragDropMooTools.htm")
        ele1= self.driver.find_element(By.ID,'dragger')
        ele2= self.driver.find_element(By.XPATH,"/html/body/div[2]")
        action = ActionChains(self.driver)
        action.drag_and_drop(ele1,ele2).perform()
        action.click_and_hold(ele1).release(ele2).perform()
        action.click_and_hold(ele1).move_to_element(ele2).perform()
        sleep(3)
    def test_keys(self):
        # 模拟键盘操作
        self.driver.get("http://sahitest.com/demo/label.htm")
        ele = self.driver.find_element(By.XPATH,"/html/body/label[1]/input")
        ele.click()
        action = ActionChains(self.driver)
        action.send_keys("username").pause(1)# 添加一秒等待
        action.send_keys(Keys.SPACE).pause(1)
        action.send_keys("张三").pause(1)
        action.send_keys(Keys.BACK_SPACE).perform()
        sleep(3)

TouchAction
官方文档
TouchAction 示例滑动页面

class TestTouchAction():
    def setup(self):
        option = webdriver.ChromeOptions()
        option.add_experimental_option('w3c', False)
        self.driver = webdriver.Chrome(options=option)
        self.driver.get("http://baidu.com")
        self.driver.implicitly_wait(5)

    def teardown(self):
        self.driver.close()

    def test_scrollbottom(self):
        ele_se = self.driver.find_element(By.ID, 'kw')
        ele_se.send_keys('selenium测试')
        ele_c =  self.driver.find_element(By.ID, 'su')

        action = TouchActions(self.driver)
        action.tap(ele_c)
        action.perform()
        # 滑动页面
        action.scroll_from_element(ele_se, 0, 1200).perform()
        sleep(3)
表单
  • 表单定义
    1. 表单是一个包含表单元素的区域
    2. 表单元素是允许用户在表单中输入信息的元素
    3. 表单使用标签<form>定义
    4. 操作表单元素步骤
      a. 首先要定位到表单元素
      b. 然后操作元素(点击、输入、清空)
class TestFrom:
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.get("http://testerhome.com/account/sign_in")
        self.driver.implicitly_wait(5)

    def teardown(self):
        self.driver.close()

    def test_form(self):
        self.driver.find_element(By.ID, 'user_login').send_keys('abcdee')
        self.driver.find_element(By.ID, 'user_password').send_keys('12312312')
        self.driver.find_element(By.XPATH, '//*[text()[contains(.,"记住")]]').click()
        self.driver.find_element(By.XPATH, '//*[@id="new_user"]/div[4]/input').click()
        sleep(3)

多窗口,frame处理

  • selenium 处理多窗口
  1. 多个窗口识别
    a. 获取当前窗口句柄:driver。current_window_handle
    b. 在获取所有窗口句柄 driver。window_handles
    c. 判断是否想要操作的窗口,如果是就可以对窗口进行操作,如果不是跳转到另外一个窗口,对另一个窗口操作 driver.switch_to_window

  2. 多个窗口切换

from time import sleep

from selenium.webdriver.common.by import By

from web_ui.base import Base
class TestWindows(Base):
    def test_windows(self):
        self.driver.get("http://www.baidu.com")
        self.driver.find_element(By.LINK_TEXT, '登录').click()

        self.driver.find_element(By.XPATH, '//*[text()[contains(.,"立即注册")]]').click()
        # 获取当前所有窗口
        windows = self.driver.window_handles
        print(windows)
        # 切换到最最新打开的窗口
        self.driver.switch_to_window(windows[-1])
        self.driver.find_element(By.ID,'TANGRAM__PSP_4__userName').send_keys('username')
        self.driver.find_element(By.ID,'TANGRAM__PSP_4__phone').send_keys('13200001234')
        sleep(2)
        #切换到 最开始的窗口
        self.driver.switch_to_window(windows[0])

        self.driver.find_element(By.ID,'TANGRAM__PSP_11__footerULoginBtn').click()
        self.driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('abcdef')
        sleep(2)

  • frame 分类,frameset、frame、iframe
    frameset 不会影响正常定位,可以用id、name 定位
    frame和iframe 需要特殊操作

  • selenium处理 frame

  1. 多个frame识别
    有两种,嵌套的、非嵌套
  2. 多个frame之前切换
    driver.switch_to.frame() # 根据ID或者index切换frame
    driver.switch_to_default_content() # 切换到默认frame
    driver.switch_to.parent_frame() # 切换到父级frame
    未嵌套iframe
    driver.switch_to_frame('frame id')
    driver.switch_to_frame('frame-index')无id用索引处理,从0开始
   def test_frame(self):
        self.driver.get('http://runoob.com/try/try.php?filename=jqueryui-api-droppable')
        # 根据 id切换frame
        self.driver.switch_to_frame('iframeResult')
        print(self.driver.find_element(By.ID, 'draggable').text)
        #切换到 父级frame
        self.driver.switch_to.parent_frame()
        # 切换到默认frame
        self.driver.switch_to.default_content()
        print(self.driver.find_element(By.ID, 'submitBTN').text)
多浏览器处理
from  selenium import  webdriver
import os
class Base():
    def setup(self):
        browser = os.getenv('browser')
        if browser == 'firefox':
            self.driver = webdriver.firefox()
        elif browser == 'headless':
            self.driver = webdriver.PhantomJS()
        else:
            self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(5)
        self.driver.maximize_window()
    def teardown(self):
        self.driver.quit()
执行java script
    def test_javascript(self):
        # 通过js滑动到页面底部
        self.driver.get("http://www.baidu.com")
        self.driver.find_element(By.ID,'kw').send_keys('selenium测试')
        # 通过 js 获得元素
        ele = self.driver.execute_script("return document.getElementById('su')")
        ele.click()
        self.driver.execute_script("document.documentElement.scrollTop=100")
        sleep(2)
        # sleep(1)
        print(self.driver.execute_script('return document.title;return JSON.stringify(performance.timing)'))
        for code in [
            'return document.title','return JSON.stringify(performance.timing)'
        ]:
            print(self.driver.execute_script(code))
  • 修改日期
    def test_wirte_time(self):
        self.driver.get('http://12306.cn/index')
        # 执行js让输入框可编辑
        time_ele = self.driver.execute_script('a=document.getElementById("train_date");a.removeAttribute("readonly")')
        sleep(3)
        # 写入值
        self.driver.execute_script('a=document.getElementById("train_date");a.value = ("2021-08-09")')
        #  清楚元素的,readonly属性
        self.driver.execute_script("arguments[0].removeAttribute('readonly')",findElement(self.driver,'xm_cpsj'))
        self.driver.execute_script(f"$arguments[0].attr('value','{cpsj}');",findElement(self.driver,'xm_cpsj'))

        sleep(2)
        # 打印元素  value
        print(self.driver.execute_script("return document.getElementById('train_date').value"))
  • 文件上传弹窗处理
    # 上传图片
    def test_upload(self):
        self.driver.get("http://www.baidu.com")
        self.driver.find_element(By.CLASS_NAME, 'soutu-btn').click()
        sleep(2)
        self.driver.find_element(By.CLASS_NAME, 'upload-pic').send_keys('x.jpg')
        sleep(3)
    def test_alter(self):
        self.driver.get('http://runoob.com/try/try.php?filename=jqueryui-api-droppable')
        self.driver.switch_to_frame('iframeResult')
        drag = self.driver.find_element(By.ID,'draggable')
        drop = self.driver.find_element(By.ID, 'droppable')
        action = ActionChains(self.driver)
        action.drag_and_drop(drag,drop).perform()
        sleep(2)
        print('点击 alter 确认')
        self.driver.switch_to_alert().accept()
        self.driver.switch_to.default_content()
        self.driver.find_element(By.ID,'submitBTN').click()
        sleep(3)

PageObject设计模式 PageObject原理及六大原则

  • 公共方法代表页面提供的功能
  • 不暴露页面元素信息
  • 不在页面内断言(在业务层做断言)
  • 方法应该返回别的 PageObject或用于断言的数据
  • 不要给整个页面建模
  • 同样的行为不同的结果,应建模成不同的方法
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 摘要: 之前用Selenium做UI自动化测试从初学到熟练碰到过很多问题,这里就不一一细说了,所以把最基本的操作都...
    Vicky_习惯做唯一阅读 11,487评论 1 23
  • 一、自动化测试所属分类(站在代码可见度角度分类) 1. 黑盒测试(功能测试)2. 灰盒测试(接口测试)3. 白盒测...
    MAVIS_42bf阅读 933评论 0 0
  • 参考链接: web自动化测试教案:http://www.cnblogs.com/zidonghua/p/74300...
    永杰gg阅读 1,115评论 0 0
  • 一、概念 互联网软件的开发和发布,已经形成了一套标准流程,最重要的组成部分就是持续集成(Continuous in...
    __65a0阅读 900评论 0 4
  • 完善融宝UI自动化框架 继续总结自动化测试API "29.模拟键盘单个按键/组合按键操作," # import t...
    公子小白123阅读 1,088评论 0 1