自动化测试就是把人对软件的测试行为转化为由机器执行测试行为的一种实践,对于最常见的GUI自动化测试来讲,就是由自动化测试模拟之前需要人工在软件界面上的各种操作,并且自动验证其结果是否符合预期
什么样的项目适合自动化
需求稳定,不会频繁变更 研发和维护周期长,需要频繁执行回归测试 需要在多种平台上重复运行相同测试的场景 性能、兼容性通过手工测试无法实现,或者手工测试成本太高 被测软件的开发较为规范,能够保证系统的可测试性 测试人员具备一定的编程能力
自动化测试用例的设计原则
自动化测试一般集中在需要重复测试的基本功能、基本业务流以及正向路径操作,不要将复杂的异常测试、复杂业务流程操作等加入到自动化测试用例中
自动化测试用例应尽量保持用例之间的独立性,最好不要形成依赖关系
自动化测试如果对数据进行了修改,在测试结束后应尽量保持还原,避免对其他用例执行产生影响
每个自动化测试用例只能验证一个功能点
webdriver的环境配置
from selenium import webdriver
webdriver工作原理
元素定位locate 元素操作operate 结果断言verificate 异常处理except
常用的八种定位方式
id
name
class name(特指具有class属性的元素)
tag name
link text
partial link text
xpath(可以在chrome中用$x调试)
1.可以通过位置进行定位
2.可以通过任意的属性来定位
绝对路径表示法:指从/目录开始的路径表示法,必须根据实际路径逐级表示
相对路径表示法:指从目标对象所在位置根据其父对象进行路径表示的方法
Chrome调试
css selector(可以在chrome中用$$调试)
1.可以通过位置进行定位
2.可以通过任意的属性来定位
利用元素的标签或元素的单一属性定位(id,class等)
多属性定位
标签+属性组合
层级(子孙)定位
Chrome调试
元素定位方法选择
页面有id时,优先使用id来定位,其次是name
xpath定位性能不是特别好,其他方法定位不到时使用xpath来定位
定位一组相同元素时,使用tag name或name
定位链接时,使用link text或partial link text
定位元素的注意事项
找到待定位元素的唯一属性
如果该元素没有唯一属性,则先找到能被唯一定位到的父元素/子元素/相邻元素,再使用xpath或css选择器等进行基于位置的定位
不要使用随机唯一属性定位
find_element和find_elements的区别
元素操作
设置等待时间
1.强制/固定等待
优点:用法非常简单,一般用于项目调试,或者用于等待元素状态、文本发生改变
劣势:等待时间固定,如果脚本中大量使用会导致脚本运行效率低
2.隐式等待/全局等待
设置一次后(隐式等待只需要设置一次),全局有效,在元素没有出现时最多只等待指定时间,但如果在等待时间内,什么时候元素出现什么时候停止等待 driver.implicitly_wait(30)
隐式等待只能在元素不存在这种情况才能生效,否则不会产生任何等待效果
3.显式等待
可针对每一个元素进行单独设置,等待条件更加灵活 如果显式等待和隐式等待同时设置,以最长等待时间为准
title_is (strtitle):判断当前页面的title是否精确等于预期
title_contains(strtitle):判断当前页面title是否包含指定字符串
presence_of_element_located(locator):判断某个元素是否被加到了dom树里,并不代表该元素一定可见
visibility_of_element_located(locator):判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
invisibility_of_element_located(locator):判断某个元素是否不可见
element_to_be_clickable(locator):判断某个元素中是否可见并且是enable的,这样的话才叫clickable
text_to_be_present_in_element(locator):判断某个元素中的text是否包含了预期的字符串
常用操作
frame
在web应用中经常出现frame的嵌套应用,假设页面上有A和B两个frame,B在A内,具体思路:
使用switch_to.frame()方法,把当前定位的主题切换到B frame里
使用switch_to.default_content()从B frame切换回A frame
文件上传
只对于 type="file",浏览器所提供的文件上传
多窗口切换
driver.switch_to().window(handle)
定位悬浮菜单
from selenium.webdriver.common.action_chains import ActionChains
对于ajax类型的下拉菜单的操作
通过unittest框架创建测试
1.必须继承于unittest.TestCase类
2.可以定义setUp和tearDown方法进行初始化,也可以使用setUpClass和tearDownClass来进行初始化
3.所有测试方法必须以test开头。测试方法会在运行时自动被调用
4.可以pycharm自带的unittest框架运行,也可以以普通方式运行
以python自带的unittest框架来运行测试类
凡是显示Run 'Unittests for...'这种菜单,就表示以pycharm内置的unittest模块来运行文件
经过设置后,以普通的py文件运行的结果
setUp:每个测试方法执行前执行一次
tearDown:每个测试方法结束后执行一次
setUpClass:整个测试执行前执行一次
tearDownClass:整个测试执行后执行一次
通过unittest框架添加断言
自动化用例管理TestLoader类
loadTestsFromTestCase()
loadTestsFromModule()
loadTestsFromNames()
discover()
import unittest
from selenium import webdriver
class demo(unittest.TestCase):
def setUp(self) -> None:
self.driver=webdriver.Chrome()
self.url='http://localhost:8080/mms'
def tearDown(self) -> None:
self.driver.quit()
def test_login_success(self):
self.driver.get(self.url)
self.driver.find_element('id','username').send_keys('admin')
self.driver.find_element('id', 'password').send_keys('admin123')
self.driver.find_element('xpath','//input[@value="Login"]').click()
msg=self.driver.find_element('id','loginName').text
self.assertEqual(msg,'admin')
def test_login_failed_without_username(self):
self.driver.get(self.url)
self.driver.find_element('id','password').send_keys('admin123')
self.driver.find_element('xpath','//input[@value="Login"]').click()
msg=self.driver.find_element('xpath','//div[contains(text(),"不能为空")]').text
self.assertEqual(msg,'User Id不能为空')
if __name__=='__main__':
unittest.main()
生成测试报告
使用HTMLTestRunner生成测试报告
1.配置方法(将HTMLTestRunner_cn.py放到python的site-packages目录下)
2.生成测试报告
3.在报告中添加截图图片
4.失败重试功能
from HTMLTestRunner_cn import HTMLTestRunner
添加截图到测试报告中
retry为重试操作,save_last_try true(只保留最后一次截图) false(每一次测试截图都保留)
智能封装等待实例
在unittest框架中使用参数化
1.安装ddt
2.参数化的几种形式 参数值为单个参数形式 参数值为组合参数形式 从函数中返回参数值 从文件中返回参数值
所谓参数化,是指利用不同的测试数据来测试相同的场景。为了提高代码的复用性,增加代码效率而采用一种代码编写的方法,叫参数化,也就是数据驱动,达到测试数据和测试业务 分离的效果
import unittest
from selenium import webdriver
import time
class demo(unittest.TestCase):
def setUp(self) -> None:
self.driver=webdriver.Chrome()
self.url="http://localhost:8080/mms"
self.data_test=[
('','admin123','User Id不能为空'),
('admin','','password不能为空'),
('adminx','admin123','没有此用户'),
('admin','xxxxx','密码错误')
]
def tearDown(self) -> None:
self.driver.quit()
def test_login_success(self):
self.driver.get(self.url)
self.driver.find_element('id','username').clear()
self.driver.find_element('id','username').send_keys('admin')
time.sleep(1)
self.driver.find_element('id', 'password').clear()
self.driver.find_element('id','password').send_keys('admin123')
time.sleep(1)
self.driver.find_element('xpath','//input[@value="Login"]').click()
time.sleep(1)
msg=self.driver.find_element('id','loginName').text
self.assertEqual(msg,'admin')
def test_login_failed(self):
self.driver.get(self.url)
for item in self.data_test:
self.driver.find_element('id', 'username').clear()
self.driver.find_element('id','username').send_keys(item[0])
time.sleep(1)
self.driver.find_element('id', 'password').clear()
self.driver.find_element('id','password').send_keys(item[1])
time.sleep(1)
self.driver.find_element('xpath','//input[@value="Login"]').click()
time.sleep(1)
errmsg=self.driver.find_element('xpath',"//div[contains(text(),'{}')]".format(item[2])).text
time.sleep(1)
self.assertEqual(errmsg,item[2])
self.driver.find_element('xpath','//span[contains(text(),"确定")]').click()
if __name__=='__main__':
names=unittest.defaultTestLoader.loadTestsFromTestCase(demo)
suite=unittest.TestSuite(names)
unittest.TextTestRunner().run(suite)
参数值为单个参数
参数值为组合参数
从函数中返回参数值
从文档中返回参数值
通过异常处理的方式实现断言失败后再截图
通过装饰器的方式实现断言失败后再截图



