一、conf
1、options.py options函数的封装
'''
options函数的封装
'''
from selenium import webdriver
# 创建一个options函数
def get_options():
options = webdriver.ChromeOptions()
# 页面加载策略
options.page_load_strategy = 'normal'
# 窗体最大化:默认启动的浏览器是窗体最大化
options.add_argument('start-maximized')
# 指定浏览器的启动坐标:只针对未最大化窗体的浏览器对象
# options.add_argument('window-position=500,500')
# 指定浏览器的窗体大小
# options.add_argument('window-size=1500,1500')
# 去除浏览器中的自动化测试黄条(警告条):这个东西现在用处不大
options.add_experimental_option('excludeSwitches', ['enable-automation', 'enable-logging'])
# options.add_experimental_option('disable-infobars') # 无效,因为是python27的版本才有效。
# 无头模式:浏览器不以界面化的形态运行。但是实际上该执行的操作还是依旧会正常执行,可以降低GPU和CPU的方式。无头模式依旧会在特殊情况下出现问题,例如Jenkins之中
# options.add_argument('--headless') # 有选择性地使用就好。一般在并发测试用例时可以考虑使用。
# 去除账号密码保存弹窗
prefs = {
'credentials_enable_service': False,
'profile.password_manager_enable': False
}
options.add_experimental_option('prefs', prefs)
# 加载本地缓存信息:通过driver对象启动的浏览器默认是不会加载本地缓存的。
'''
加载本地缓存信息的时候一定注意,启动代码前要关闭所有当前正在运行的浏览器
本身缓存文件也是文件的一种,如果有已经启动的浏览器,则该文件就已经处于使用状态,所以再启动浏览器会报错。
这也是一种绕过登录的操作方式,也就意味着绕过了验证码
'''
# options.add_argument(r'--user-data-dir=C:\Users\15414\AppData\Local\Google\Chrome\User Data')
# 启动隐身模式
# options.add_argument('incognito')
# 去除控制台的多余信息:常规信息的去除,首先用这个去掉日志
# options.add_experimental_option('excludeSwitches', ['enable-logging'])
# 去除控制台的多余信息:有效的,进一步避免多余信息的手段。
options.add_argument('--log_level=3')
options.add_argument('--disable-gpu')
options.add_argument('--ignore-certificate-errors')
# 要将设置好的options对象进行返回,一定要记得return
return options
2、read_yaml.py yaml文件读取
'''
yaml文件的读取
'''
import yaml
# 读取yaml文件中的内容,并返回值
def read(file):
file = open(file, 'r', encoding='utf-8')
values = yaml.load(stream=file, Loader=yaml.FullLoader)
return values
# print(read('../test_data/login.yaml'))
二、test_cases 测试用例
1、test_fecmall.py 关键字驱动下的测试用例
'''
关键字驱动类模式下实现的pytest测试执行:
1. 基于同一个driver对象来实现,避免在测试过程中出现多个浏览器,导致运行的时间会更加缓慢
2. 所有的操作内容,都是基于已登录状态来实现的,除去登录本身。
3. 针对用例本身执行的内容,需要做Fixture的设计,看哪些内容适合于在Fixture中进行定义
4. 基于pytest会关联到setup和teardown,要合理化设计对应的内容
5. 业务层级的Fixture可以再考虑再设计,但是一定要结合整体业务逻辑去进行思考。
6. 对于pytest本身,是否需要定义pytest.ini和conftest.py来解决测试过程中有可能会需要解决的问题。
测试用例的内容,还是尽可能详细进行编写。毕竟只是写一次的东西
'''
import os
from time import sleep
import allure
import pytest
from class30_pytest_auto.conf.read_yaml import read
# 商城的登录操作
# def test_login(driver, login):
# sleep(2)
# driver.open('http://www.baidu.com')
@allure.epic('实现fecmall商品的下单流程')
@allure.feature('商品下单功能')
@allure.story('实现商品下单到支付页面的流程')
@allure.title('商品下单与支付')
@allure.step('下单与支付')
@pytest.mark.parametrize('login', read('../test_data/login.yaml'), indirect=True)
@pytest.mark.parametrize('data', read('../test_data/order.yaml'))
# 添加商品订单
def test_order(driver, login, data):
'''
该用例用于实现在登录后,对fecmall进行的定点测试商品添加购物车流程
'''
try:
with allure.step('实现测试数据处理'):
url, data = data['url'], data['data']
with allure.step('访问商品详情页'):
driver.open(url)
with allure.step('输入购买数量'):
driver.input(**data['num'])
with allure.step('点击添加购物车按钮'):
driver.click(**data['button'])
with allure.step('流程末尾的校验'):
driver.assert_text(**data['assert'])
with allure.step('运行流程末尾的截图'):
1 / 0
allure.attach(driver.get_screenshot_as_png(), '最终结尾', allure.attachment_type.PNG)
# with allure.step('运行后的等待'):
# sleep(5)
except:
with allure.step('运行失败,进行截图'):
allure.attach(driver.get_screenshot_as_png(), '失败截图', allure.attachment_type.PNG)
raise
# 收藏商品
def test_add(driver):
try:
# 访问指定的商品详情页
driver.open(
'http://hcc.fecmall.com/pair-of-stylish-button-embellished-hollow-out-mesh-shape-knitted-boot-cuffs-for'
'-women')
# 点击收藏该产品
driver.click('partial link text', '收藏该产品')
driver.wait(5)
1 / 0
except:
with open('../temp/1.png', 'wb') as file:
file.write(driver.get_screenshot_as_png())
raise
# 修改个人信息
def test_edit_info():
pass
if __name__ == '__main__':
pytest.main(['-sv', './test_fecmall.py', '--alluredir=./report_allure'])
os.system('allure generate ./report_allure -o ./report --clean')
三、test_data 测试数据
1、login_yaml 登录yaml文件
-
url: http://hcc.fecmall.com/customer/account/login
data:
user:
by: id
value: email
txt: 123@qq.com
pwd:
by: id
value: pass
txt: 3333
button:
by: id
value: js_registBtn
2、order.yaml 下单yaml文件
-
url: http://hcc.fecmall.com/off-the-shoulder-long-sleeve-high-low-day-dress-green#product_page_info
data:
num:
by: name
value: qty
txt: 10
button:
by: id
value: js_registBtn
assert:
by: xpath
value: //button[@title="Proceed to Checkout"]/span/span
expected: 继续支付
三、web_keys
1、web_keys.py 关键字驱动类
'''
关键字驱动类
'''
from time import sleep
from selenium import webdriver
from class17_options.options import get_options
# 基于用户需要,创建对应浏览器对象
def open_browser(type_):
# if type_ == 'chrome ':
# driver = webdriver.Chrome()
# elif
if type_ == 'Chrome':
driver = webdriver.Chrome(options=get_options())
else:
try:
driver = getattr(webdriver, type_)()
except:
driver = webdriver.Chrome()
return driver
# 这只是一种思路。能够解决问题的方式有万千,多去思考。
# def open_browser_plus(type_):
# '''
# 你无法判断用户会输入什么样的内容,很可能不会遵循你的要求,例如:
# Chrome:chrome,google chrome,Chrome,gc,谷歌浏览器
# '''
# # 定义一个浏览器的完整内容
# browser = {
# 'Chrome': ['chrome', 'google chrome', 'Chrome', 'gc']
# }
# for key, value in browser.items():
# if type_ in value:
# driver = getattr(webdriver, key)()
# break
# return driver
# 关键字驱动类
class WebKeys:
# 临时的driver对象
# driver = webdriver.Chrome()
# 构造函数
def __init__(self, type_):
self.driver = open_browser(type_)
self.driver.implicitly_wait(5)
# 访问url
def open(self, url):
self.driver.get(url)
# 元素定位
def locator(self, by, value):
return self.driver.find_element(by, value)
# 输入
def input(self, by, value, txt):
el = self.locator(by, value)
el.clear()
el.send_keys(txt)
# 点击
def click(self, by, value):
self.locator(by, value).click()
# 关闭
def quit(self):
self.driver.quit()
# 强制等待
def wait(self, time_):
sleep(int(time_))
# 悬停
def above(self):
pass
# 切换句柄:解决三个方法才能解决的问题。
def switch_handle_new(self, close=None, num=1):
handles = self.driver.window_handles
if close is not None:
self.driver.close()
self.driver.switch_to.window(handles[num])
# 切换句柄
def switch_handle(self):
handles = self.driver.window_handles
self.driver.switch_to.window(handles[1])
# 切换句柄
def switch_handle_with_close(self):
handles = self.driver.window_handles
self.driver.close()
self.driver.switch_to.window(handles[1])
# 切换句柄
def switch_handle_default(self):
handles = self.driver.window_handles
self.driver.switch_to.window(handles[0])
# 文本断言:in包含文本的形式来断言
def assert_text_in(self, by, value, expected):
try:
reality = self.locator(by, value).text # 定义实际结果
message = f'''
断言失败:
expected:{expected}
reality:{reality}
{expected} != {reality}
'''
assert expected in reality, message
return True
except:
return False
# 文本断言:判断文本是否一致的形式来断言
def assert_text(self, by, value, expected):
reality = self.locator(by, value).text # 定义实际结果
message = f'''
断言失败:
expected:{expected}
reality:{reality}
{expected} != {reality}
'''
assert expected == reality, message
# 实现截图
def get_screenshot_as_png(self):
return self.driver.get_screenshot_as_png()
# 登录
# def login(self):
# self.input() # 账号
# self.input() # 密码
# self.click() # 点击登录按钮
四、根目录下的 conftest.py
1、conftest.py Fixture编写
'''
定义在测试过程中会有的Fixture
1. 如果想生成不同的driver对象,则可以通过调用不同的Fixture即可
2. 所有操作行为都离不开login的相关行为,所以封装login的Fixture
'''
import pytest
from class30_pytest_auto.web_keys.web_keys import WebKeys
# driver对象的初始化,不同的用例py文件可能会关联不同的测试内容,需要分开管理driver对象
@pytest.fixture(scope='module')
def driver(request):
# 添加teardown
def driver_finalizer():
driver.quit()
# 注册teardown
request.addfinalizer(driver_finalizer)
# driver生成逻辑
driver = WebKeys('Chrome')
return driver
# 生成IE浏览器示例
@pytest.fixture(scope='module')
def ie_driver():
driver = WebKeys('Ie')
return driver
# 实现login的Fixture定义
@pytest.fixture
def login(driver, request):
# 基于yaml文件解析获取的参数内容
url, data = request.param['url'], request.param['data']
# 访问url
driver.open(url)
# 账号输入
driver.input(**data['user'])
# 密码输入
driver.input(**data['pwd'])
# 确认按钮的点击
driver.click(**data['button'])