自动化-Notes

常用命令

#对pip进行升级
python -m pip install --upgrade pip

#selenium安装:
pip install selenium==版本号
pip install selenium==错误的版本号,会显示所有可安装的版本

#查看版本
pip show selenium

概念

1、web自动化测试

  • 让程序代替人工自动验证web项目功能的过程

2、什么Web项目适合做自动化测试

  • 需求变动不频繁

  • 项目周期长

  • 项目需要回归测试

3、web自动化开始进行阶段

  • 手工测试之后(1,时间问题2,功能不完善)

4、自动化测试分类

  • web自动化测试

  • 移动自动化测试(app自动化)

  • 接口自动化(工具,代码)

  • 单元测试

5、web自动化测试所属分类(代码可见度)

  • 黑盒测试(功能测试)

  • 白盒测试(单元测试)

  • 灰盒测试(接口测试)

6、web自动化测试属于黑盒测试(功能测试)

7、主流测试工具

  • QTP 收费(支持web,自动化)
  • selenium(免费,开源,只支持web项目)
  • Robot fromwork:基于python扩展关键字驱动

8、selenium:一个web自动化测试工具

特点:

  • 开源,免费

  • 跨平台(Linux , windows, mac)

  • 支持多浏览器:火狐,谷歌,ie

  • 支持多语言:python ,Java,c

  • 成熟稳定

  • 功能强大,支持商业化大部分功能,并且由于开源,可以定制化需求功能

9、元素定位依赖于

  • 标签名
  • 属性
  • 层级
  • 跨径

定位方式

  • id
  • name
  • class_name
  • tag_name
  • link_text
  • partial_link_text
  • xpath
  • css
# 引入selenium库相关模块
from time import sleep
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By

# 实例化Edge浏览器的webdriver对象
driver = webdriver.Edge()

try:
    # 打开本地注册页面
    url = "file:///D:/Repositories/GitCode/html_login_register/register.html"
    driver.get(url)

    # id定位元素并填写表单
    driver.find_element(By.ID,"username").send_keys("admin")
    driver.find_element(By.ID,"password").send_keys("123456")
    driver.find_element(By.ID,"password2").send_keys("123456")
    
    #name定位元素并填写表单
    #driver.find_element(By.NAME,"username").send_keys("admin")
    #driver.find_element(By.NAME,"password").send_keys("123456")
    #driver.find_element(By.NAME,"password2").send_keys("123456")
    
    #class_name定位元素并填写表单(实际写入的是class属性值)
    #driver.find_element(By.CLASS_NAME,"form-control").send_keys("admin")
    #driver.find_element(By.CLASS_NAME,"form-control").send_keys("123456")
    #driver.find_element(By.CLASS_NAME,"form-control").send_keys("123456")
	
    #tag_name定位元素并填写表单(写入input)
    #driver.find_element(By.TAG_NAME,"input").send_keys("admin")
    
    #link_text(精准匹配)与partial_link_text(模糊匹配)定位超链接a标签
    #driver = webdriver.Edge()
    #url = "https://www.runoob.com/"
    #driver.get(url)
    #driver.find_element(By.LINK_TEXT,"【学习 HTML】XXXX").click()
    #driver.find_element(By.PARTIAL_LINK_TEXT,"【学习 HTML】").click()
    
    #xpath定位元素并填写表单
    #driver.find_element(By.XPATH,"/html/body/div[@id='center']/form[@id='myform']/div[@class='input-group'][1]/input[@id='username']").send_keys("admin")
    #driver.find_element(By.XPATH,"/html/body/div[@id='center']/form[@id='myform']/div[@class='input-group'][2]/input[@id='password']").send_keys("123456")
    
    #CSS定位元素并填写表单
    #driver.find_element(By.CSS_SELECTOR,"#username").send_keys("admin")
    #driver.find_element(By.CSS_SELECTOR,"input#password.form-control").send_keys("123456")
    #driver.find_element(By.CSS_SELECTOR,"#password2").send_keys("123456")
    
    # 等待3秒
    sleep(3)

# 捕获WebDriverException异常(可能由于网络、浏览器驱动等原因导致)
except WebDriverException as e:
    print(e)

finally:
    # 关闭WebDriver
    driver.quit()

为什么使用XPATH和css 定位

  • id,name,class依赖于这三个元素对应的属性,如果元素没有以上三个属性,定位方法不能使用

  • link_text和partial_link_text只适合超链接

  • tag_name:只能找页面唯一元素,或者多个相同元素中的第一个元素

11、汇总:

  • 基于元素属性特有定位方式(id/name/class_name)

  • 基于元素标签名称定位:tag_name

  • 定位超链接文本(link_text,pattial_link_text)

  • 基于元素路径定位(xpath)

  • 基于选择器(css)

浏览器常用API

  • driver.maximize_window() 窗口最大化

  • driver.set_window_size(w,h) 设置窗口大小

  • driver.set_window_position(x,y)设置窗口位置

  • driver.back() 后退

  • driver.forward() 前进

  • driver.refresh()刷新

  • driver.close()关闭当前窗口

  • driver.quit()关闭驱动对象

  • driver.title获取页面title

  • driver.current_url获取当前页面url

# 导入sleep函数
from time import sleep 
# 导入WebDriverException
from selenium.common.exceptions import WebDriverException 
# 导入webdriver模块
from selenium import webdriver
# 导入By类
from selenium.webdriver.common.by import By 

# 实例化Edge浏览器的webdriver
driver = webdriver.Edge()

try:
    # 指定URL并打开
    url = "file:///D:/Repositories/GitCode/html_login_register/login.html"
    driver.get(url)
    # 最大化浏览器窗口
    driver.maximize_window()
    sleep(2)
    # 设置浏览器窗口大小
    driver.set_window_size(500,300)
    sleep(2)
    # 设置浏览器窗口位置
    driver.set_window_position(320,150)
    # 根据CSS选择器找到注册按钮元素并点击
    driver.find_element(By.CSS_SELECTOR,"#register").click()
    sleep(2)
    # 返回上一个页面
    driver.back()
    sleep(2)
    # 前进到下一个页面
    driver.forward()
    sleep(2)

# 捕获WebDriverException异常并打印
except WebDriverException as e:
    print(e)

# 关闭webdriver
finally:
    driver.quit()

获取元素信息

  • driver.size 返回元素大小

  • driver.text 返回元素的文本

  • driver.get_attribute("id") 获取属性值,传递的参数为元素的属性名

  • element.is_displayed() 判断元素是否可见

  • element.is_enabled() 判断元素是否可用

  • element.is_selected() 判断元素是否选中,用来检查复选框或单选按钮是否被选中

test和size调用时无括号

get_attribute一般应用场景:判断一组元素是否为想要的元素或者判断元素属性值是否正确

is_displayed,is_enabled,is_selected在特殊应用场景中使用

鼠标操作

提示:selenium框架中,虽然提供了鼠标右击方法,但是没有提供选择右击菜单的方法,可以通过发送快捷键的方式解决(经测试,谷歌浏览器不支持)

#导包
from selenium.webdriver.common.action_chains import ActionChains

#实例化
action = ActionChains(driver)
#鼠标事件常用的操作方法:
1.context_click()  #右击   
应用:action.contex_click(元素定位).perform()

2.double_click()  #双击
应用:action.double_click(元素定位).perform()

3.drag_and_drop()  #拖拽
应用:action.drag_and_drop(控制的元素,指定位置).perform()

4.move_to_element()  #悬停  
应用:action.move_to_click(元素定位).perform()

5.perform()  #执行以上事件方法

键盘操作

#导包
from selenium.webdriver.common.keys import Keys
#定位用户名
username=driver.find_element(By.NAME,"username")
#输入文本
username.send_keys("15679790909")
#删除文本
username.send_keys(Keys.BACK_SPACE)
#全选文本
username.send_keys(Keys.CONTROL,"a")
#复制文本
username.send_keys(Keys.CONTROL,"c")
#粘贴文本
driver.find_element(By.NAME,"password").send_keys(Keys.CONTROL,"v")

元素等待

  • 为什么设置元素等待:由于网络或配置,未第一时间加载出来,而抛出未找到元素异常

  • 什么是元素等待:元素在第一次未找到时,元素等待设置的时长被激活,如果在设置的有效时长内找到元素,继续执行代码,如果超出设置的时长未找打元素,抛出未找到元素异常

  • 元素等待分类:1、隐式等待 2、显示等待

隐式等待(全局)

driver.implicitly_wait(timeout)
#(timeout:为等待最大时长,单位秒)

显示等待(局部)

导包->from selenium.webdriver.support.wait import webDriverWait

#参数:
#timeout : 超时时间
#poll frequency : 访问频率,默认0.5秒
#x: x 为driver,它是WebDriverWait类将传入的driver赋值给类self._driver,until方法调用了self.driver
WebDriverWait(driver,timeout=10,poll_frequency=0.1).until(lambda x:x.find_element(By.NAME"username")).send_keys("15679790909")

扩展

send_keys("文件名") 可以上传文件

driver.find_element(By.NAME,"password").send_keys("D:\hello.txt")

忽略警告

import warnings
warnings.filterwarnings("ignore")

API操作

下拉框

可以使用css直接定位

缺点:如果option选项没有value值的话,css定位或其他定位就不太方便

解决:select类

#1.导包:from selenium.webdriver.suport.select import Select
#2.实例化:s=Select(element)
#3.调用方法:s.select_by_index()

select_by_index(1)  #通过下标索引定位
select_by_value("sh") # 通过value值
select_by_visible_text("上海") # 通过文本

注意事项:

  1. 实例化select时,需要的参数为select标签元素
  2. 调用Select类下面的方法,是通过索引,value属性值,显示文本去控制,而不需要click()

警告框

对话框类型

  • alert 警告框

  • confirm 确认框

  • prompt 提示框

如何处理:

步骤:

1.切换到对话框
方法:driver.switch_to.alert

2.处理对话框
driver.switch_to.alert.text 获取文本
driver.switch_to.alert.accept() 同意
driver.switch_to.alert.dismiss() 取消

滚动条

selenium 中没有直接定位滚动条的方法,可以通过js语句间接控制

操作
1.设置js语句:
js="window.scrollTo(0,1000)"
0:x轴向右  1000:y轴向下

2.调用js方法
driver.execute_script(js)

切换Frame表单

frame,iframe

为什么切换?

当前主目录内没有iframe表单页面元素信息,不切换,找不到元素

如何切换

方法:driver.switch_to.frame("id\name\element")

为什么要回到主目录:

iframe或frame只有在主目录采用相关元素信息,不回到主目录,切换语句会报错

如何回到主目录:

方法:driver.switch_to.default_content()

driver.switch_to.parent_frame()

切换frame时,可以使用name,id,iframe元素

多窗口切换

为什么要切换多窗口

页面存在多个窗口时,selentium默认焦点只会在主窗口上的所有元素,不切换窗口,无法操作主窗口以外的窗口元素

如何切换

思路:获取要切换的窗口句柄,调用切换方法进行切换

方法:

1. driver.current_window_handle  获取当前主窗口句柄
2. driver.window_handles  获取当前由driver启动的所有窗口句柄
3. driver.switch_to.window(handle)	切换到指定窗口

#步骤:
1. 获取当前窗口句柄
2. 点击连接,启动另一个窗口
3. 获取当前所有窗口句柄
4. 遍历所有窗口句柄
5. 判断当前遍历的窗口句柄不等于主窗口句柄
6. 切换窗口操作
#示例
handle=diver.current_window_handle
i=diver.window_handles
for j in i:
    if j!=handle:
        diver.switch_to.window(j)

截屏

方法:

driver.get_screenshot_as_file(imagepath)

多次产生截图,可以使用时间戳的形式进行区分

操作:

#导包->import datetime
#strftime:将时间转为字符串函数
driver.get_screenshot_as_file('../Img/%s.png'%(datetime.strftime("%Y_%m_%d %H_%M_%S")))

验证码

作用:防止恶意请求

处理方式

1.去掉验证码;项目在测试环境,公司自己的项目

2.设置万能验证码;测试环境或线上环境,公司自己的项目

3.使用验证码识别技术;识别效率低,不推荐

4.使用cookie;推荐

cookie

由服务器生成:

作用:标记一次对话的状态(登录的状态)

使用:浏览器自动记录cookie,在下一条请求时将cookie信息自动附加请求

应用:

方法:driver.get_cookie() 获取所有的coolie

driver.add_cookie({字典}) 设置cookie

#步骤:
#1. 打开百度url  driver.get("http://www.baidu.com")
#2. 设置cookie信息:  driver.add_cookie({"name":"BDUSS","value":"根据实际情况编写"})
#3. 暂停2秒以上
#4. 刷新操作
from time import sleep
from selenium import webdriver
driver = webdriver.Edge()
driver.get("https://www.baidu.com/")
# 创建字典存储 cookie
cookie_dict = {
    "name": "BDUSS",
    "value": "xxxx"
}
# 添加 cookie 到 WebDriver
driver.add_cookie(cookie_dict)
sleep(5)
#获取所有cookies信息
cookies = driver.get_cookies()
print("cookies信息为:",cookies)
print('-----------------------')
for cook in cookies:
    print(cook['name'])
#刷新,必须进行刷新才能看到效果
driver.refresh()
driver.implicitly_wait(3)
driver.quit()

UnitTest框架

特点

  • 批量执行用例

  • 提供丰富的断言知识

  • 可以生成报告

python自带的一种单元测试框架

核心要素

  • TestCase测试用例

  • TestSuite测试套件

  • TextTestRunner以文本的形式运行测试用例

  • TestLoader批量执行测试用例-搜索指定文件夹内指定字母开头的模块

  • Fixture固定装置,两个固定的函数,一个初始化使用,一个结束的时候使用

TestCase

说明:测试用例

步骤:

  1. 导包->import unittest
  2. 定义测试类->新建测试类必须继承unittest.TestCase
  3. 定义测试方法->测试方法命名必须以test开头

运行:

​ 1.运行测试类所有的测试方法,光标定位到类当前行右键运行

​ 2.运行单个测试方法:光标放到测试方法当前行。

#Demo:编写求和函数
#导包
import unittest
#编写求和函数
def add(x,y):
    return x+y
#定义测试类并继承
class Test01(unittest.TestCase):
    #定义测试方法 注意:以test字母开头
    def test_add(self):
        #调用测试的函数
        result =  add(1,1)
        print("结果为:",result)
    def test_add02(self):
        #调用测试的函数
        result =  add(1,2)
        print("结果为:",result)
        print("__name__内置变量获取当前运行的模块名称:",__name__)

# __name__:python中内置变量
# 1、如果当前运行的模块是当前模块:__name__的值为:__main__
# 2、如果当前运行的模块不是主模块:__name__的值为:模块名称(只要进行了导包并引用)
if __name__ == '__main__':
    unittest.main()

Test Suite

提示:需要配合TestRunner才能被执行

说明:测试套件

步骤:

  1. 导包
  2. 获取测试套件对象,suite = unittest.TestSuite()
  3. 调用addTest()方法,添加测试用例

添加测试用例方法:

  1. suite.addTest(类名("方法名称")) #添加指定类中指定的测试方法
  2. suite.addTest(unittest.makeSuite(类名)) #添加指定类中所有以test开头的方法
#导包
import unittest
from WebTest.UnitTest框架.test_01_TestCase import Test01
from WebTest.UnitTest框架.test02 import Test02

if __name__ == '__main__':
    #实例化suite对象
    suite = unittest.TestSuite()
    #调用添加方法
    #写法一 类名("方法名") 注意:方法名称使用双引号
    suite.addTest(Test01("test_add"))
    suite.addTest(Test01("test_add02"))
    #扩展:添加测试类中所有test开头的方法
    suite.addTest(unittest.makeSuite(Test02))
    #执行测试套件
    runner = unittest.TextTestRunner()
    runner.run(suite)

TextTestRunner

说明:执行测试套件方法

步骤:

  1. 导包
  2. 实例化后去执行套件对象 runner = unittest.TextTestRunner()
  3. 调用run方法执行runner.run(suite)

TestLoader

说明:

​ 1、将符合条件的测试方法添加到测试套件中

​ 2、搜索指定文件夹下指定字母开头的模块下test开始的方法,并将这些方法添加到测试套件中,最后返回测试套件

操作:

  • 导包

  • 调用Test Loader()

  • 执行测试套件

    • suite = unittest.TestLoader().discover("目录",“指定字母开头模块文件”)
import unittest
#调用方法,查找cases目录下的所有py文件
suite01 = unittest.TestLoader().discover("./cases")
#扩展:查找cases目录下所有以test开头的py文件
suite02 = unittest.TestLoader().discover("./cases",pattern="test*.py")
#扩展:defaultTestLoader=TestLoader(),注意:没有括号
suite03 = unittest.defaultTestLoader.discover("./cases")
#执行测试套件方法
unittest.TextTestRunner().run(suite03)

TestSuite和TestLoader区别

共同点:都是测试套件

不同点:实现方式不同

  • TestSuite:要么添加指定的测试类中所有test开头的方法,要么添加指定测试类中指定某个test开头的方法

  • TestLLoader:搜索指定目录下指定字母开头的模块中以test字母开头的方法并将这些方法添加到测试套件中,最后返回测试套件

Fixture

说明:装置函数(setUp、tearDown)

级别:

  • 函数级别:def setUp() / def tearDown()

  • 类级别:def setUpClass() / def dearDownClass()

  • 模块级别:def setUpModule() / sef tearDownModule()

提示:无论使用函数级别还是类级别,最后常用场景为:

初始化:

  • 获取浏览器实例化对象

  • 最大化浏览器

  • 隐式等待

结束:

  • 关闭浏览器驱动对象
#fixture其实就是两个函数,这两个函数可以一起使用,也可以单独使用
#   1、初始化函数:def setUp()
#   2、结束函数:def tearDown()
#   fixture级别:
#       1、函数级别(常用)
#       2、类级别
#       3、模块级别(常用)

# 引入unittest模块
import unittest
# 定义初始化模块函数setUpModule()
def setUpModule():
    print("setUpModule")
# 定义结束模块函数tearDownModule()
def tearDownModule():
    print("tearDownModule")
# 定义测试类Test03
class Test03(unittest.TestCase):
    # 定义初始化类方法setUpClass()
    @classmethod
    def setUpClass(cls) -> None:
        print("setUpClass被执行")
    # 定义结束类方法tearDownClass()
    @classmethod
    def tearDownClass(cls) -> None:
        print("tearDownClass被执行")
    # 定义初始化函数setUp()
    def setUp(self) -> None:
        print("setUp被执行")
    # 定义结束函数tearDown()
    def tearDown(self) -> None:
        print("tearDown被执行")
    # 定义第一个测试函数test01()
    def test01(self):
        print("test01被执行")
    # 定义第二个测试函数test02()
    def test02(self):
        print("test02被执行")

#执行顺序:模块>类>函数
# setUpModule
# setUpClass被执行
# setUp被执行
# test01被执行
# tearDown被执行
# setUp被执行
# test02被执行
# tearDown被执行
# tearDownClass被执行
# tearDownModule

UnitTest断言

什么是断言

  • 让程序代替人工判断执行结果是否与预期结果相等的过程

为什么要断言

  • 自动化不写断言,相当于没有执行

常用断言

  • self.assertEqual(a,b) 判断a是否等于b

  • self.assertIn(a,b) 判断b是否包含a

  • self.assertTure(a)判断a是否为True

import unittest
#unittest常用断言
#   1、asserTrue:如果结果为True通过,否则失败
#   2、assertEqual:判断两个字符串是否相等
#   3、assertIn:判断后边的字符串是否包含前边的字符串
#   4、assertIsNone:判断是否为None
class Test02(unittest.TestCase):
    def test001(self):
        # 断言是否为True
        flag = True
        flag =False
        self.assertTrue(flag)
        self.assertFalse(flag)

        # 判断两个字符串是否相等
        # self.assertEqual("hello","hell0")

        # 判断后边的字符串是否包含前边的字符串
        # self.assertIn("hello jack","hello jack,joker")

        #判断是否为None
        # flag = None
        # self.assertIsNone(flag)
        # self.assertIsNotNone(flag)

Demo

输入错误密码进行断言捕获异常

import unittest
from selenium import webdriver
from time import sleep
from datetime import datetime
from selenium.webdriver.common.by import By
#定义测试类并继承unittest.TestCase
class Test_YML(unittest.TestCase):
    #定义初始化方法
    def setUp(self) -> None:
        #获取浏览器驱动对象
        self.driver = webdriver.Edge()
        #打开url
        self.driver.get("http://192.168.226.143:8080/EasyBuy/Login?action=loginOut")
        #最大化浏览器
        self.driver.maximize_window()
        #隐式等待
        self.driver.implicitly_wait(10)
    def tearDown(self) -> None:
        #关闭浏览器
        sleep(2)
        self.driver.quit()

    def test_login_code_null(self):
        driver = self.driver
        #点击登录链接
        driver.find_element(By.PARTIAL_LINK_TEXT,"登录").click()
        #输入用户名
        driver.find_element(By.CSS_SELECTOR,"#loginName").send_keys("szz")
        #输入密码
        driver.find_element(By.CSS_SELECTOR,"#password").send_keys("1234")
        #点击登录
        driver.find_element(By.CSS_SELECTOR,".log_btn").click()
        #获取登录后提示信息
        result = driver.find_element(By.XPATH,".//*[@id='showMessage']").text
        print("result:",result)
        #定义预期结果
        expect_result = "密码错误"
        try:
            #断言
            self.assertEqual(result,expect_result)
        #只捕获断言错误
        except AssertionError:
            #截图
            driver.get_screenshot_as_file("../Img/{}.png".format(datetime.strftime("%Y_%m_%d %H_%M_%S")))
            #抛出异常
            raise

扩展

断言有两种方法:

方法1:unittest框架中断言

方法2:使用python自带的断言

  1. assert a==b 判断a是否等于b
  2. assert a in b 判断 b是否包含a
  3. assert True/1 判断是否为true

参数化

from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
#字典参数化
user_dict = {
    "admin":"admin",
    "124":"124",
    "125":"125",
    "126":"126",
    "127":"127",
    "128":"128"
}
for username,password in user_dict.items():
    driver = webdriver.Edge()
    driver.get("http://192.168.226.141:8080/hr/index.do")
    driver.find_element(By.ID,"username").send_keys(username)
    driver.find_element(By.ID,"password").send_keys(password)
    driver.find_element(By.CLASS_NAME,"right-button01").click()
    print("当前登录用户:%s,密码:%s"%(username,password))
    sleep(2)
    driver.refresh()
    driver.quit()

#元组参数化
# user_Tuple = (
#     111,
#     222,
#     333,
#     444
# )
# for username in user_Tuple:
#     driver = webdriver.Edge()
#     driver.get("http://192.168.226.141:8080/hr/index.do")
#     driver.find_element(By.ID,"username").send_keys(username)
#     driver.find_element(By.ID, "password").send_keys("1234")
#     driver.find_element(By.CLASS_NAME, "right-button01").click()
#     print("当前登录用户:%s"%username)
#     sleep(2)
#     driver.refresh()
#     driver.quit()

#数据分离式参数化
# import data
# for username,password in data.user_dict.items():
#     driver = webdriver.Edge()
#     driver.get("http://192.168.226.141:8080/hr/index.do")
#     driver.find_element(By.ID,"username").send_keys(username)
#     driver.find_element(By.ID,"password").send_keys(password)
#     driver.find_element(By.CLASS_NAME,"right-button01").click()
#     print("当前登录用户:%s,密码:%s"%(username,password))
#     sleep(2)
#     driver.refresh()
#     driver.quit()

解决冗余问题

根据需求动态获取参数并引用

解决相同业务逻辑,不同测试数据问题

应用插件

导包:from parameterized import parameterized

修饰测试函数 @parameterized.expand(数据)

数据格式

1.单个参数,类型为列表

2.多个参数,类型为列表嵌套元组

3.在测试函数中的参数设置变量引用参数值,变量的数量必须和数据值的个数相同

class testCae(unittest.TestCase):
    @unittest.expectedFailure("1","2","3")
    def test_add(self,num):
        resukt =add(2,3)
        print(num)

跳过方法

分类:

​ 直接跳过:语法:@unittest.skip(说明)

一般功能为实现完成用例

​ 条件满足跳过:语法:@unittestif.skip(说明)

判断条件满足,就不执行

以上两种都可以修饰类和函数

HTML测试报告

根据Text Test Runner改编而来

操作

  1. 导包 ->from xx.HTMLTestRunner import HTMLTestRunner
  2. 定义测试套件suite=unittest.defaultTestLOader.discover("../casse",patten="test*.py")
  3. 实例化HTMlTestRunner类,并调用run方法执行测试套件

with open(报告存放路径,“wb”)as f

注:生成html报告,必须使用wb,以二进制形式写入

  • 实例化HTMLTestRunner类

HTMLTestRunner(stream=f).run(测试套件)

import unittest
from Tools.HTMLTestRunner import HTMLTestRunner
from datetime import datetime
case = unittest.defaultTestLoader.discover("./Case",pattern="test_hr.py")
if __name__ == '__main__':
    report_dir = './Report/{}.html'.format(datetime.now().strftime("%Y_%m_%d %H_%M_%S"))
    with open(report_dir,"wb") as f:
        runner = HTMLTestRunner(stream=f,verbosity=1,title="人力资源管理系统测试报告",description="Test Case Result:")
        runner.run(case)
    f.close()

PO模式

版本

  • V1:不采用任何模式(线性模型)
  • V2:采用测试框架unittest
  • V3:业务代码和页面对象进行
  • V4:实际中的po模式编写

案例

  1. 账号不存在
  2. 密码错误

问题

​ v1无法批量运行

​ v2业务脚本和页面对象没有分开

​ v3代码冗余量大

PO介绍

PO:page(页面) object(对象)

v4版本

page继承base,scripts调用page

​ 结构:

​ 1、base(基类):page页面一些公共的方法;

  • 初始化方法
  • 查找元素对象
  • 点击元素对象
  • 输入方法
  • 获取文本方法
  • 截图方法

​ 2、page(页面对象):一个页面封装成一个对象;

​ 应用:继承base;

​ 3、scripts(业务层):导包调用page页面;

​ 注意:

​ 以上方法封装的时候,解包只需一次,在查找元素解包

driver为虚拟,谁调用base时,谁传入,无需关注从哪来

loc真正使用loc的方法只有查找元素方法使用

2.page(页面对象):一个页面封装成一个对象

​ 应用:继承base

实现:

  1. 模块名。page+实际操作模块名称 如:page_login.py
  2. 页面对象名:以大驼峰方法将模块名抄进来,有下划线的去掉下划线
  3. 方法:涉及元素,将每个元素操作单独封装一个操作方法
  4. 组装:根据需求组装以上操作步骤:

3.scripts(业务对象):导包,调用page页面

实现:

  1. 模块:test+实际操作模块名称 如:test login.py
  2. 测试业务名称,以大驼峰方法将模块名抄进来,有下划线的去掉下划线
  3. 方法:

初始化方法:setup()

​ 实例化页面对象

​ 前置操作:如打开等等

结束方法 tearDown()

关闭驱动

测试方法:根据要操作的业务来实现

扩展:loc变量:类型为元组,*loc为解包

数据驱动:

说明:通过测试数据控制用例的执行,直接影响测试结果

数据驱动是最好结合po+参数化技术使用

优点:将维护关注点放到测试数上,而不去关注测试脚本代码

数据驱动常用的格式:

  1. json
  2. Excel
  3. csv
  4. txt

json介绍

  1. 一种纯文本格式,后缀.json:
  2. 一种轻量级数据交换格式:(接口数据传递基本使用json格式)
  3. 由键值对组成,和python的字典格式一模一样,不同之处在于(json是文本格式)
  4. json语法:花括号包含键值对,键与值之间使用冒号(:)分隔,键值对之间使用逗号(,)分隔

json与字典转换

字典转为json字符串

方法:json.dumps()

字符串转字典

方法:json.loads()

json的写与读

需要导包

写入:方法:demp(写什么文件,往哪写)

读取:方法:load()

查找元素判断是否操作成功 思路封装

def base_if_success():

try:

​ self.base_find_element(loc,timeout=2)

​ return True

except:

​ return Palse

如何区分正向逆向用例

思路:在测试数据中添加一个表示正向或逆向用例的标记:如:True/False

步骤:

1.调用登录方法(此登录方法中,只有输入用户名,输入密码,输入验证码,点击验证码,点击登录按钮)切记:不要封装点击登录链接地址:

2.判断是否正向用例:

​ 判断安全退出是否存在

​ 点击安全退出

​ 点击登录链接地址

否则

​ 获取异常信息

​ 断言操作

​ 点击异常提示框确定按钮

日志

说明:记录系统运行程序一些步骤,对一个事件(点击事件),也称为日志

特点:

  1. 调试程序
  2. 定位跟踪bug
  3. 根据日志,查看系统运行是否出错
  4. 分析用户行,与数据统计

级别:

  1. debug调试级别
  2. info信息
  3. warning警告
  4. error错误
  5. critical严重

开发常用以上:debug,info,warning,error

测试常用级别:info,error

logging的基本使用

步骤:

  1. 导包
  2. 调用相应的级别方法,记录日志信息 logging.debug("debug.....")

设置级别

logging.basicConfig(level=logging.DEBUG)

提示:

  1. 默认级别为:logging.WARNING
  2. 设置级别是调用的是logging文件夹下面的常量,而不是调用的小写方法
  3. 切记:设置级别后,日志信息只会记录大于等于此级别的信息
posted @ 2023-05-18 18:55  璀璨如歌  阅读(28)  评论(0)    收藏  举报