专栏首页北京宏哥python+ selenium自动化测试

python+ selenium自动化测试

1. 简介

  本来上一篇就是练习篇的最后一篇文章了,但是有的小伙伴私下反映说是做了那么多练习,没有一个比较综合的demo练练手。因此宏哥在这里又补存了一些常见的知识点进行练习,在文章最后也通过实例给小伙伴们或者童鞋们进行了一个登录模块的自动化测试的实例,其他的你可以照猫画虎地轻松的搞定和实现。

2. python-web自动化-三种等待方式

当有元素定位不到时,比如下拉框,弹出框等各种定位不到时;

一般是两种问题:1 、有frame ;2、没有加等待

下面学习三种等待方式:

2.1 强制等待 sleep(xx)或者Time.sleep

是在程序运行过程中使用time模块中的sleep进行代码的休眠进行强制等待,是显式等待中的一种极端情况。

这种方法简单粗暴,不管浏览器是否加载完,程序都要等待规定的xx时间,时间到了才继续执行下面的代码。

不建议总是用这种等待方式,会严重影响程序的执行速度。通过time模块中sleep进行代码的暂停,但是实际使用过程中,如果都以sleep进行控制严重影响了程序的运行。

2.1.1 参考代码1
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

import time

# 强制等待——代码休眠

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
time.sleep(3)

driver.quit()
2.1.2 参考代码2
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

from selenium import webdriver
from time import sleep
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
sleep(3)#强制性等待3s再执行以下代码
print(driver.current_url)
driver.quit()#退出驱动,关闭所有窗口

2.2 隐性等待 implicitly_wait(xx)

这种方法是设置一个最长的等待时间,如果在规定时间内网页全部元素加载完成,则执行下一步,否则一直等待时间截止才执行下一步。比强制性等待智能些

!隐性等待对整个driver的周期都起作用,所以只要设置一次即可

2.2.1 参考代码1
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from time import ctime

driver = webdriver.Firefox()

# 设置隐式等待为10秒
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")

try:
    print(ctime())
    driver.find_element_by_id("kw22").send_keys('selenium')
except NoSuchElementException as e:
    print(e)
finally:
    print(ctime())
    driver.quit()

这里可以看到在10秒内没有找到想要找到的元素,但是依旧执行了10秒,然后报错,如果修改代码为可以找到,代码执行非常迅速。

implicitly_wait()默认参数的单位为秒,本例中设置等待时长为10秒。首先这10秒并非一个固定的等待时间,它并不影响脚本的执行速度。其次,它并不针对页面上的某一元素进行等待。当脚本执行到某个元素定位时,如果元素可以定位,则继续执行;如果元素定位

不到,则它将以轮询的方式不断地判断元素是否被定位到。假设在第6秒定位到了元素则继续执行,若直到超出设置时长(10秒)还没有定位到元素,则抛出异常。

2.2.2 参考代码2
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.baidu.com/')
driver.implicitly_wait(30)#隐性等待,最长30s
print(driver.current_url)
driver.quit()

2.3.显性等待 WebDriverWait

WebDriverWait配合该类的until()和until_not()方法,根据条件灵活的等待

程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。

显式等待是你在代码中定义等待一定条件发生后再进一步执行你的代码。

A. 使用前,先引用相关库

B. 确定元素的定位表达式

C. 使用expected_conditions对应的方法来生成判断条件

WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.ID,ele_locator)))
WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.XPATH,ele_locator)))

D. 调用WebDriverWait类设置等待总时长、轮询周期

2.3.1 参考代码1
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

#A. 使用前,先引用相关库
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
 
driver = webdriver.Chrome()#打开Chrome浏览器
driver.get('https://www.baidu.com/')#打开百度
driver.find_element_by_xpath('//div[@id="u1"]//a[@name="tj_login"]').click()#点击【登录】;click() 方法,可模拟在按钮上的一次鼠标单击。
# B. 确定元素的定位表达式
ele_locator = "TANGRAM__PSP_10__footerULoginBtn"#通过id,确定‘用户名登录’元素
 
# C.  使用expected_conditions对应的方法来生成判断条件
# EC.方法名(定位方式,定位表达式)
# EC.visibility_of_element_located(By.ID,ele_locator)#元素可见
 
# D.  调用WebDriverWait类设置等待总时长、轮询周期
# WebDriverWait(driver, 超时时长, 调用频率(默认0.5s)).until(可执行方法, 超时时返回的信息)
# 等待10秒钟,每隔1秒去查看对应的元素是否可见;如果可见,继续下一步操作;如果不可见,则继续等待,直到10s结束,如果元素还是不可见,则抛出超时异常
WebDriverWait(driver,10,1).until(EC.visibility_of_element_located((By.ID,ele_locator)))

driver.find_element_by_id('TANGRAM__PSP_10__footerULoginBtn').click()#点击【用户名登录】
 
driver.close()#关闭当前窗口
2.3.2 参考代码2
# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: 《手把手教你》系列练习篇之9-python+ selenium自动化测试
'''

# 3.导入模块

from time import ctime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

dr = webdriver.Chrome()
dr.get('https://www.baidu.com')

try:
    print(ctime())
    element = WebDriverWait(dr, 10).until(
        EC.presence_of_element_located((By.ID, "kw"))
    )
    # WebDriverWait(driver=self.driver, timeout=300, poll_frequency=0.5,  ignored_exceptions=None)
    # driver:浏览器驱动
    # timeout:最长超时等待时间
    # poll_frequency:检测的时间间隔,默认为500ms
    # ignore_exception:超时后抛出的异常信息,默认情况下抛 NoSuchElementException 异常
    print("我已找到")
finally:
    print(ctime())
    dr.quit()

执行结果:

以上代码执行后就发现,整段代码执行速度非常快,即使我在WebDriverWait中设置10秒,也不会等待10秒的情况,因为在不到一秒内,已经完成了加载并定位id为“kw”的元素。

通过WebDriverWait 和 ExpectedCondition 组合使用,让我们的代码执行只需要等待需要的时长,而不是固定的时长,这样最大限度的节省时间。

此外ExpectedCondition类中提供了很多预期条件判断方法,省去了再创建包的功夫:

"""
title_is:判断当前页面的title是否等于预期
title_contains:判断当前页面的title是否包含预期字符串
presence_of_element_located:判断某个元素是否被加到了dom树里,并不代表该元素一定可见
visibility_of_element_located:判断某个元素是否可见. 可见代表元素非隐藏,并且元素的宽和高都不等于0
visibility_of:跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了
presence_of_all_elements_located:判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是'column-md-3',那么只要有1个元素存在,这个方法就返回True
text_to_be_present_in_element:判断某个元素中的text是否 包含 了预期的字符串
text_to_be_present_in_element_value:判断某个元素中的value属性是否包含了预期的字符串
frame_to_be_available_and_switch_to_it:判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False
invisibility_of_element_located:判断某个元素中是否不存在于dom树或不可见
element_to_be_clickable - it is Displayed and Enabled:判断某个元素中是否可见并且是enable的,这样的话才叫clickable
staleness_of:等某个元素从dom树中移除,注意,这个方法也是返回True或False
element_to_be_selected:判断某个元素是否被选中了,一般用在下拉列表
element_located_to_be_selected
element_selection_state_to_be:判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be:跟上面的方法作用一样,只是上面的方法传入定位到的element,而这个方法传入locator
alert_is_present:判断页面上是否存在alert
"""

另外这里使用了until()函数也可以使用until_not()

  until_not(method, message='')

  调用该方法体提供的回调函数作为一个参数,直到返回值为False

  until(method, message='')

  调用该方法体提供的回调函数作为一个参数,直到返回值为True

3. 下拉框or弹框

通常情况下,在网页中会有一些下拉框进行选择或者给你一个弹框告诉你需要进行确认,遇到这样的情况如何解决呢,宏哥在这里就来简单地说一说……‘’

3.1 代码实现:

3.2 参考代码:

# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-09
@author: 北京-宏哥   QQ交流群:705269076
Project: python+ selenium自动化测试练习篇8
'''

# 3.导入模块

import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.select import Select


driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
time.sleep(5)

# driver.find_element(By.ID, "kw").send_keys("selenium&python")
# driver.find_element(By.ID, "su").click()
# driver.find_element(By.XPATH, '/html/body/div[1]/div[5]/div[1]/div[2]/div[1]/div[2]/div[1]').click()
# driver.find_element(By.XPATH, '/html/body/div[1]/div[5]/div[1]/div[2]/div[1]/div[1]/span[2]').click()
# 折腾半天才发现定位出来的不是下拉框……
driver.find_element(By.LINK_TEXT, '设置').click()
driver.find_element(By.LINK_TEXT, '搜索设置').click()
time.sleep(2)

sel = driver.find_element(By.XPATH, '//*[@id="nr"]')  # 定位下拉框
Select(sel).select_by_value('50')  # 通过value的值进行选定条目
driver.find_element(By.CLASS_NAME, 'prefpanelgo').click()
time.sleep(2)
driver.switch_to.alert.accept()  # 此处同意警告框提示内容
time.sleep(2)

driver.quit()

3.3 运行结果:

运行代码后,控制台打印如下图的结果

3.4 浏览器

浏览器跳转到设置页面,会提示“已记录下您的偏好”

在百度首页想要进行设置每次搜索页面显示的数目,就会有一个下拉框进行选择,这里可以导入Select这个模块进行对下拉框进行选择,通常下拉框的列表是包含一个值的,这样就可以通过value来选定,完成设置之后,当然是要保存设置啦,点击保存发现,居然有

一个弹框,这可如何是好,切换至alert之后接受吧……

通过在编辑器中的提示,我们同样可以给弹框发送一个值,当然这里设置中并没有出现这类情况。

这次对下拉框和弹框的处理过程中,折腾了不短时间,原因就是元素等待的问题,下回要仔细研究下元素等待的问题了。

4. 自动化测试demo

使用selenium进行测试,当然是需要进行验证的,此时结合python的断言函数就变得非常有用了。测试中设定好预期,当实际情况与预期有差别,给出错误信息,好像正是所希望的。

来一段简单的代码看下断言的基本使用:

# coding:utf-8

import time

from selenium import webdriver

dr = webdriver.Chrome()
dr.maximize_window()

dr.get("https://www.baidu.com")
print(dr.title)

try:
    assert (dr.title == "百度,你就知道")
except:
    print('标题错误,请查看错误信息')

time.sleep(5)
dr.quit()

获取页面的title是否符合我们的预期,当打开的网页title不是我们想要的,不仅从函数assert的提示信息看到原因,也可输出简单的提示信息。

Web登录测试是很常见的测试,手动测试大家再熟悉不过了,那如何进行自动化登录测试呢!本文就基于python+selenium结合unittest单元测试框架来进行一次简单但比较完整的cnblog自动化登录测试,可提供点参考!下面就包括测试代码和每种测试情况的截图。

另一种方式是结合python测试框架unittest进行验证。以下的代码只是为了演示:

# coding=utf-8?

# 1.先设置编码,utf-8可支持中英文,如上,一般放在第一行

# 2.注释:包括记录创建时间,创建人,项目名称。
'''
Created on 2019-12-10
@author: 北京-宏哥   QQ交流群:705269076
Project: python+ selenium自动化测试练习篇9
'''

# 3.导入模块

import unittest
from selenium import webdriver
from time import sleep
'''
cnblog的登录测试,分下面几种情况:
(1)用户名、密码正确
(2)用户名正确、密码不正确
(3)用户名正确、密码为空
(4)用户名错误、密码正确
(5)用户名为空、密码正确(还有用户名和密码均为空时与此情况是一样的,这里就不单独测试了)
'''

class LoginCase(unittest.TestCase):

    def setUp(self):
        self.dr = webdriver.Chrome()
        self.dr.maximize_window()

    # 定义登录方法
    def login(self, username, password):
        self.dr.get('https://passport.cnblogs.com/user/signin')  # cnblog登录页面
        self.dr.find_element_by_id('LoginName').send_keys(username)
        self.dr.find_element_by_id('Password').send_keys(password)
        self.dr.find_element_by_id('submitBtn').click()

    def test_login_success(self):
        '''用户名、密码正确'''
        self.login('北京-宏哥', '!qaz2wsx')  # 正确用户名和密码
        sleep(3)
        link = self.dr.find_element_by_id('lnk_current_user')
        self.assertTrue('北京-宏哥' in link.text)  # 用assertTrue(x)方法来断言  bool(x) is True 登录成功后用户昵称在lnk_current_user里
        self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_success.jpg")  # 截图  可自定义截图后的保存位置和图片命名

    def test_login_pwd_error(self):
        '''用户名正确、密码不正确'''
        self.login('北京-宏哥', 'kemi')  # 正确用户名,错误密码
        sleep(2)
        error_message = self.dr.find_element_by_class_name('ajax-error-box').text
        self.assertIn('用户名或密码错误', error_message)  # 用assertIn(a,b)方法来断言 a in b  '用户名或密码错误'在error_message里
        self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_pwd_error.jpg")

    def test_login_pwd_null(self):
        '''用户名正确、密码为空'''
        self.login('北京-宏哥', '')  # 密码为空
        error_message = self.dr.find_element_by_id('Password-error').text
        self.assertEqual(error_message, '请输入密码')  # 用assertEqual(a,b)方法来断言  a == b  请输入密码等于error_message
        self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_pwd_null.jpg")

    def test_login_user_error(self):
        '''用户名错误、密码正确'''
        self.login('北京-宏哥1', '!qaz2wsx')  # 密码正确,用户名错误
        sleep(2)
        error_message = self.dr.find_element_by_id('ajax-error-box').text
        self.assertIn('用户名或密码错误', error_message)  # 用assertIn(a,b)方法来断言 a in b
        self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_user_error.jpg")

    def test_login_user_null(self):
        '''用户名为空、密码正确'''
        self.login('', '!qaz2wsx')  # 用户名为空,密码正确
        error_message = self.dr.find_element_by_id('LoginName-error').text
        self.assertEqual(error_message, '请输入登录用户名')  # 用assertEqual(a,b)方法来断言  a == b
        self.dr.get_screenshot_as_file("D:\\cnblogtest\\login_user_null.jpg")

    def tearDown(self):
        sleep(2)
        print('自动测试完毕!')
        self.dr.quit()


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

通过以上代码,我们可以看到使用selenium和unittest框架结合,已经可以对用户登陆的模块做一个简单的自动化测试。

但是现在博客园的登陆机制的改变有可能部分用例不成功,但是你知道怎么做就可以了。

测试截图如下:

正确用户名和密码登录成功!

用户名正确,密码为空

用户名为空,密码正确

5. 小结

好了,今天的分享就到这里吧!!!谢谢各位的耐心阅读。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • selenium frame 切换

    不得不提到switch_to_frame(),很多人在这样写的时候会发现,这句话被划上了删除线,原因是这个方法已经out了,之后很有可能会不支持,建议的写法是s...

    十四君
  • Redis大批量上传数据 使用shell与python脚本

    需求是:有大量的ip地址,作为分布式爬虫的任务分配,需要加入到redis队列中,如果使用数据库提取+for+redis-lpush的方式速度非常慢,大约放80w...

    十四君
  • mysql-使用load两分钟-千万行表快速迁移合成亿行总表

    使用load这种底层的迁移方式,会让移动速度非常快。将已经导出为txt的7.2G数据合成为接近1亿行的总表,大致耗时2分钟。

    十四君
  • c语言函数库学习~sscanf~格式化输入

    今天算是被打击到了吧,由郑轻的acm老师来我学院指导安排了个现场的小比赛,,俺们居然有还是输给一个大一的新手,,哎,情何以堪,,所以还是要重视下基础编程能力的培...

    十四君
  • 用django1.11.2版本实现文件上传demo

    之前参考了虫师和纯臻对此的实践博文,但是由于版本迭代问题,最新版本的Django命令已经修改了,我重新完成一份攻略。

    十四君
  • docker ubuntu:14.04上 安装 python-PIL-image环境

    因为在采集中有图像解析的需求,如今将爬虫架构部署在docker中,需要配置一个PIL中image包的情况,因错误较多。故记录下来。

    十四君
  • Linux下,删除大于固定大小的文件

    十四君
  • 常用selenium浏览器配置

    selenium webdriver在get()方法会一直等待页面加载完毕才会执行后面的,可如果加载时间太长会导致后续操作无法进行。有时我们要的信息已经加载出来...

    十四君
  • mac 下安装scrapy 解决oserror问题

    http://stackoverflow.com/q/31900008/6403672

    十四君
  • git push后出现everything up-to-date 采用分支的解决办法

    学习自:http://www.tuicool.com/articles/zeaQjav

    十四君

扫码关注云+社区

领取腾讯云代金券