9.python+selenium

python+selenium自动化

自动化脚本编写原则:LOVE原则
    L:Locate,定位
    O:Operate,操作
    V:Verify,断言
    E:Except,异常处理

注:python自带库第三方库是使用pip install 包名  安装的,
    安装完成后都会在\Lib\site-packages文件夹下面


1. 安装工具
    1-1.安装selenium
        在DOS窗口执行: pip install selenium

    pip install selenium -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

        检查是否安装成功:pip show selenium
                
            如果安装失败,执行命令:pip install -U selenium
                                  pip install --user -U selenium
        
    1-2.安装浏览器,注意浏览器与驱动版本要对应
            Chrome(不区分64/32位)驱动:https://npm.taobao.org/mirrors/
            火狐版本及驱动映射:https://github.com/mozilla/geckodriver/releases/

    1-3.将下载好的压缩包解压后chromedriver.exe放到python安装路径下的Scripts文件夹下
            如 C:\Program Files\Python36\Scripts

    1-4.编写脚本,验证配置是否正确
        from selenium import webdriver
        dr = webdriver.Chrome() #获取浏览器句柄
        url = "https://www.baidu.com/"
        dr.get(url)


2. 打开网页如百度首页,打开F12,使用元素拾取器,标记输入框,可看到元素及CSS样式


3. html标签:
        input代表输入框或按钮
        a代表超链接


4. 八大元素定位方法

    4-1.根据id属性定位:
        find_element_by_id(id的值),使用条件是id的值必须为唯一,可查源码搜索

    4-2.根据name属性定位:
        find_element_by_name(name的值),使用条件是name的值必须为唯一

    4-3.根据class属性定位:
        find_element_by_class_name(class的值),使用条件同上

    4-4.根据超链接文本定位:
        find_element_by_link_text(超链接文本信息)

    4-5.根据超链接部分文本信息定位:
        find_element_by_partial_link_text(部分文本信息)

    4-6.根据标签定位:
        find_element_by_tag_name(标签名称)    较少使用

    4-7.根据xpath定位:
        4-7-1.根据绝对路径定位:
            find_element_by_xpath('/html/body/div[5]/div/span[2]/input')

        4-7-2.根据元素的单个属性定位:
            find_element_by_xpath('//input[@type="submit"]')

        4-7-3.根据元素的多个属性定位:
            find_element_by_xpath('//*[@name="wd" and @class="s_ipt"]')

        4-7-4.根据层级+元素属性定位:
            find_element_by_xpath('//span[1]/input[@id="kw"]')

    4-8.根据css定位:find_element_by_css_selector('css的语法')    定位速度快

        4-8-1.根据id属性定位 ('#id')

        4-8-2.根据class 属性定位 ('.class') 或 ('.class1.class2')  
            如果使用2个class定位失败,可以class1和class2中间加逗号

        4-8-3.根据id和class之外的属性定位 
            ('标签[属性="值"]')或 ('[属性="值"]') 或 ('[属性1="值1"][属性2="值2"]')

        4-8-4.根据层级+属性定位        (父层级>子层级[属性="值"])
                         ('span > input') 或 ('span > input#kw') 
                        或('span.bg.s_ipt_wr.quickdelete-wrap > input')
                        或('span[name="goods_id"] > input')


    问:有些元素,在谷歌浏览器上能定位,在火狐浏览器上定位失败,是什么原因呢?
            因为不同浏览器的内核不一样,他们的CSS样式不一样。


5. 浏览器元素的操作

    5-1. click()  点击

    5-2. send_keys() 向文本框输入内容

    5-3. clear()   清空文本框内容

    5-4. quit()  退出浏览器

    5-5. send_keys()  上传文件 ,只能在标签为input的元素中使用  

    5-6. text    获取元素文本信息    
            如获取右边input标签的“地图”: <input id="mapid"> 地图 </input>
            map = dr.find_element_by_id("mapid")
            print(map.text)

    5-7. get_attribute('属性名称')   获取元素属性的值 

    5-8. sleep()   固定等待 

    5-9. implicitly_wait() 隐式等待,只对webdriver开头的操作生效
            dr.implicitly_wait()

    5-10. submit()  提交表单,模拟回车键的操作

    5-11. maximize_window()   最大化窗口    dr.maximize_window()

    5-12. is_displayed()  判断元素是否在页面显示,(肉眼可见的元素才能操作)
                print(sBtn.is_displayed())        → True


    5-13. 鼠标悬停、动作生效:
        from selenium.webdriver import ActionChains  # 导包
        move_to_element()  # 将鼠标移动到对应的元素   
        perform()   # 执行所有ActionChains中存储的行为,即让悬停的动作生效

      例:找到百度首页的“更多”,鼠标移过去展开“更多”
            from selenium.webdriver import ActionChains    # 导包
            moreBtn = dr.find_element_by_name('tj_briicon')  # 定位首页元素
            ActionChains(dr).move_to_element(moreBtn).perform() #鼠标悬停生效


    5-14. 多表单切换: 
            dr.switch_to.frame(切换到的表单)    # 切换表单
            dr.switch_to.default_content()          # 切回默认表单

        某些页面(如https://mail.163.com/)采用了iframe页面嵌套,即HTML里面嵌套了
            另一个HTML,元素定位方法默认定位外层的HTML,
            如果定位里面的HTML,需要进行表单切换

      例:在网易邮箱的用户名输入内容
            email = 'https://mail.163.com/'
            dr.get(email)
            # 定位iframe
            frame = dr.find_element_by_xpath('//div[@id="loginDiv"]/iframe') 
            dr.switch_to.frame(frame)   # 切换到表单2
            username = dr.find_element_by_name('email')
            username.send_keys('iframe定位')

        多表单切换顺序为默认表单 → 表单2 → 默认表单 → 表单3 

        切回默认表单: 
            dr.switch_to.default_content()  # 切回默认表单1
            dr.switch_to.frame(‘表单3’)    # 切换到表单3


    5-15. 窗口切换
            windows = dr.window_handles   # 获取所有打开的窗口
            # print(len(windows))  # 打印列表长度
            dr.switch_to.window(windows[1])  # 切换到第2个窗口(取列表第2个元素)


    5-16. 关闭窗口     注:驱动退出或窗口关闭后,该驱动无法继续使用

            dr.close()  # 关闭当前窗口, 若关闭多个窗口,需要先切换窗口
            dr.quit()   # 关闭所有窗口,退出驱动


    5-17. 警告框处理
        # dr.switch_to.alert.text             # 获取警告框文本信息
        # dr.switch_to.alert.accept()    # 点击警告框的确认按钮
        # dr.switch_to.alert.dismiss()   # 点击警告框的取消按钮

      例:百度首页→设置→搜索设置→确定后,处理警告框
        url = "https://www.baidu.com/"
        dr.get(url)
        dr.maximize_window()
        # 定位页面右上角的设置
        setting = dr.find_element_by_css_selector('#s-usersetting-top')
        # 鼠标悬停(需要先导包)
        ActionChains(dr).move_to_element(setting).perform() 
        time.sleep(0.5)
        # 点击“搜索设置”
        dr.find_element_by_link_text("搜索设置").click()
        time.sleep(0.5)
        # 点击“保存设置”
        dr.find_element_by_link_text("保存设置").click()
        # 获取警告框文本信息
        text = dr.switch_to.alert.text
        print(text)
        # 点击警告框的确认按钮
        dr.switch_to.alert.accept()

    5-18. 下拉框元素定位
        # from selenium.webdriver.support.ui import Select  # 导包
        # Select(下拉框元素).select_by_index(下标值)
        # Select(下拉框元素).select_by_value(value属性的值)
        # Select(下拉框元素).select_by_visible_text(可见的文本值)

      例:
        from selenium.webdriver.support.select import Select  # 导包
        url = r"C:\下拉列表&只读元素&隐藏元素&滚动条练习.html"
        dr.get(url)
        ele = dr.find_element_by_css_selector('[id="s1"]')
        Select(ele).select_by_value("br2") # 定位value属性的值
        sleep(1)
        Select(ele).select_by_index(4)   # 定位0开始的第5个下拉框
        sleep(1)
        Select(ele).select_by_visible_text("selenium3")  # 定位可见的文本值

     注:下拉框元素定位,也可以先定位到下拉框,再选择元素进行操作(如点击)

    5-19. js定位
        在某些特殊情况下,浏览器的元素是无法被定位,或无法被操作的,
        比如浏览器的滚动条,元素具有readonly属性,我们需要使用稍微
        有难度一点的定位方法---调用js脚本进行定位。


    5-19-1.  滚动条处理
        # location1 = 'window.scrollTo(0,2000)'
        # dr.execute_script(location1)

      例:
        url = r"C:\下拉列表&只读元素&隐藏元素&滚动条练习.html"
        dr.get(url)
        time.sleep(1)
        location1 = 'window.scrollTo(0,500)'
        dr.execute_script(location1)
        time.sleep(1)
        location2 = "window.scrollTo(0,1700)"
        dr.execute_script(location2)
        time.sleep(1)
        location3 = "window.scrollTo(0,700);"
        dr.execute_script(location3)

    5-19-2. 若元素包含readonly属性,无法直接操作,
                需要调用JS脚本把readonly属性删掉。

      例:
        url = r"C:\下拉列表&只读元素&隐藏元素&滚动条练习.html"
        dr.get(url)
        time.sleep(1)
        # read_inputBox = """document.querySelectorAll("#s2")[0].removeAttribute("readonly")"""
        # read_inputBox = 'document.querySelectorAll("#s2")[0].removeAttribute("readonly")'
        read_inputBox = 'document.querySelectorAll(\'[id="s2"]\')[0].removeAttribute("readonly")'
        dr.execute_script(read_inputBox)
        inputBox = dr.find_element_by_css_selector("#s2")
        inputBox.send_keys("这是删除元素属性的")

      例:移除活动开始时间的readonly属性
        js = '''document.querySelectorAll('[name="start_time"]')[0].removeAttribute("readonly")'''
        # js = "document.querySelectorAll('#start_time_id')[0].removeAttribute('readonly')"  # 也可使用id定位
        js = 'document.querySelectorAll(\'[name="start_time"]\')[0].removeAttribute("readonly")'  # 也可转义符
        dr.execute_script(js)
        startTime = dr.find_element_by_css_selector('[name="start_time"]')
        startTime.clear()
        import time   # 导包一般放在前面
        now = time.strftime('%Y-%m-%d %H:%M:%S')  # 当前日期、时间
        startTime.send_keys(now)

      例:移除活动开始时间的readonly属性
          js = "document.getElementById('end_time_id').removeAttribute('readonly')"
        dr.execute_script(js)
        endTime = dr.find_element_by_id('end_time_id')
        endTime.clear()
        from datetime import date, timedelta  # 导包一般放在前面
        end = date.today() + timedelta(10)   # 日期是当前日期加10天
        end2 = str(end) + ' 23:59:59'   # 日期转换成字符串格式,再拼接上具体时间
        endTime.send_keys(end2)


6. PO设计模式
    全称是Page Object,是一种自动化测试的设计模式,它将元素定位、业务操作和测试用例分开。
    这样的好处是,当页面元素发生变化,只需要修改存放改页面元素的类即可,大大减少了脚本的维护成本。

7. 单元测试框架

    Python单元测试框架有unittest、pytest

    单元测试框架(framework),是为了解决某一类问题,而设计出来的工具。
        现状:    a. 线性脚本
                    b. 当测试用例达到量级,没有代码的组织管理
                    c. 测试用例达到成百上千条的时侯、维护困难
                    d. 没有日志用例总数、通过数、失败数量、环境信息
                    e. 没有丰富的断言方法


    # unittest总结:
    # 1. setup()、teardown(),每条用例执行前后都要运行一次,适用于一条用例,多条用例耗费时间
    # 2. setUpClass()、tearDownClass(),所有用例执行前后总共运行一次,适用于批量执行用例
    # 3. 测试用例的执行顺序依据用例名称顺序执行
    # 4. 自动化测试脚本必须要有环境恢复(删除存入数据库的内容等)    
    # 5. 环境恢复是在用例执行结束后,但自动化脚本的环境恢复代码可以紧跟在环境预置之后,不影响执行顺序
    # 6. 在同一个类里面,如果方法里面的变量需要被其他方法使用,在定义变量的时候,变量名前加上self.
    # 7. unittest.main()方法只会运行当前脚本中的测试用例(也就是方法名以test开头的)


import unittest
class MyTest(unittest.TestCase):
    # pass

    # 环境预置
    # def setUp(self):
    #     print('环境预置')

    @classmethod   # 使用setUpClass必须声明装饰器
    def setUpClass(self):    # 批量执行用例时使用
        print('环境预置')

    # 测试用例必须是test开头
    def testCase_1(self):
        # 期望结果
        expectResult = 'hello'
        actualResult = 'hello world'
        print('测试用例的操作步骤1')
        # 断言
        self.assertIn(expectResult,actualResult)

    def testCase_2(self):
        # 期望结果
        expectResult = 123
        print('测试用例的操作步骤2')
        # 断言
        self.assertEqual(expectResult,123,msg = "不相等")

    # 恢复环境
    # def tearDown(self):
    #     print('恢复环境')

    @classmethod   # 使用tearDownClass必须声明装饰器
    def tearDownClass(self):
        print('恢复环境')

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


9. 项目实战 ecshop-夺宝奇兵

        ecshop自动化        # 项目文件夹

            public        # 存放公共部分
                public.py      # 如登录等

            reports            # 存放生成的测试报告

            testCases        # 存放测试用例
                test_01_duobao.py      # 用例文件以test_开头

            myDB        # 操作数据库
                myDB.py

            HTMLTestRunner.py          # 生成报告的模块

            runAllCases.py                  # 执行所有用例,并发送邮件


    1.项目环境搭建:

        1.解压xapmm到C盘根目录,打开C:\xampp\xampp-control.exe,启动Apache和MySQL服务

        2.如果Apache服务启动失败,修改C:\xampp\apache\conf\httpd.conf 里面的端口(默认为80,假设改为8000),
            修改C:\xampp\apache\conf\extra\httpd-ssl.conf 里面的端口(默认443,假设改为4433)

        3.如果MySQL服务启动失败,修改C:\xampp\mysql\bin\my.ini 里面的端口(默认3306)

        4.将upload.zip解压后的文件夹改名为ecshop,移动到C:\xampp\htdocs 里面。

        5.查看本机IP(假如为192.168.0.110),浏览器打开 192.168.0.110:8000/ecshop,根据页面提示安装即可

        6.安装时注意:数据库搜一下选择test后覆盖,数据库用户名默认root,密码默认为空,页面底部注意安装测试数据

        7.连接mysql时,如果报1130错误,需要在C:\xampp\mysql\bin\my.ini 里面,
            [mysqld]下面增加一句话:skip-grant-tables

            如果报1045-Access denied for user 'root'@'localhost'错误,需要打开DOS窗口,切换到C:\xampp\mysql\bin,
            先输入mysql -u root -p或mysql -uroot登录,
            再输入grant all privileges on *.* to 'root'@'%' identified by '123456';  表示可以给所有ip都设定root登陆了,
                其中%也可替换成本机ip或localhost,123456也可以改成别的密码
            最后输入flush privileges; 刷新授权,之后重启mysql服务(win需要到任务器才能彻底关闭)    

            https://blog.csdn.net/qq_42036869/article/details/84671466
            https://blog.csdn.net/tspangle/article/details/37761147

        

10. 自动化扩展知识点


    1. 对验证码的常见处理方式?
            去掉验证码,
            设置万能验证码,
            用python调用OCR模块,
            调用第三方平台提供的接口进行识别,比如:斐斐打码,尖叫数据这些平台接口

    2. WebDriver原理

            浏览器的驱动,接收客户端发过来的指令(指令就是我们的脚本),
            浏览器的驱动根据接收到的指令,驱动浏览器工作。

    3. 如何提高selenium脚本的执行速度?
        1)、提高网速;
        2)、少用sleep,多用隐式等待或显式等待。


    4. 自动化的应用范围和测试用例设计
        1)、自动化测试,适用于回归测试,在功能测试之后进行。
        2)、自动化测试,适用于项目周期长,版本多,界面元素稳定的项目。
        3)、自动化测试用例的流程不要太长,不要有太多分支。
        4)、自动化测试脚本是把手工测试过的用例转换成脚本,不是所有手工用例都能转化成脚本的,如UI测试的用例,
                所以每个项目都有自己的自动化脚本转换率(我以前做过的项目,自动化脚本转换率要在40%以上)
        5)、自动化测试脚本,要包含四个部分:
                5.1 预置条件的构造。比如,你要查询某一天的数据,就要先在环境中构造这些数据;    
                5.2 操作步骤。
                5.3 结果验证。(加入断言或验证,loadrunner里叫检查点) 
                5.4 环境恢复。把执行这条脚本所用到的数据全部删掉,把环境恢复到初始状态,以    免影响后续程序的执行

    5. webdriver的工作流程(了解)
            1.WebDriver启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,做为webdriver的remoteserver.
            2.Client端通过CommandExcuter发送HTTPRequest给remoteserver的侦听端口通信协议:thewebriverwireprotocol)
            3.Remoteserver需要依赖原生的浏览器组件(如:lEDriverServer.exe、chromedriver.exe),来转化转化浏览器的native调用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值