create the new project and then I will update forever
This commit is contained in:
parent
7463c87d55
commit
f51c3052a5
14
README.md
14
README.md
|
@ -1,8 +1,8 @@
|
||||||
# 小北原创UI自动化高阶框架selenium+pytest
|
# 小北原创UI自动化高阶框架selenium+pytest
|
||||||
|
|
||||||
#### 介绍
|
#### 介绍
|
||||||
免费开源的高级selenium自动化框架,开箱即用,复用性高,可适用任何web项目中
|
免费开源的高级selenium自动化框架,开箱即用,复用性高,可适用任何web项目中
|
||||||
原创作者:小北
|
原创作者:小北
|
||||||
微信:xiaobei_upup
|
微信:xiaobei_upup
|
||||||
|
|
||||||
#### 软件架构
|
#### 软件架构
|
||||||
|
@ -37,3 +37,13 @@
|
||||||
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
|
||||||
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
||||||
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
||||||
|
|
||||||
|
|
||||||
|
# run testcases
|
||||||
|
pytest
|
||||||
|
# run allure report
|
||||||
|
pytest --alluredir ./reports testcases/pytest/test_search_baidu_index.py
|
||||||
|
# start up serve to browse report
|
||||||
|
allure serve ./reports
|
||||||
|
# run pytest to choose which you want to run
|
||||||
|
pytest -m test
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def swipe_view_by_percent(driver, x1, y1, x2, y2):
|
||||||
|
"""
|
||||||
|
滑动函数(百分比类型)
|
||||||
|
Args:
|
||||||
|
driver: appium驱动。webdriver类型
|
||||||
|
x1: 滑动起点坐标的横坐标占屏幕宽度的百分比。0<x1<1
|
||||||
|
y1: 滑动起点坐标的纵坐标占屏幕高度的百分比。0<y1<1
|
||||||
|
x2: 滑动终点坐标的横坐标占屏幕宽度的百分比。0<x2<1
|
||||||
|
y2: 滑动终点坐标的纵坐标占屏幕高度的百分比。0<y2<1
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
width = driver.get_window_size()['width']
|
||||||
|
height = driver.get_window_size()['height']
|
||||||
|
detal_x = abs(x2 - x1) * width # x坐标差值
|
||||||
|
detal_y = abs(y2 - y1) * height # y坐标差值
|
||||||
|
t = math.sqrt(detal_x ** 2 + detal_y ** 2) * 5
|
||||||
|
driver.swipe(x1 * width, y1 * height, x2 * width, y2 * height, t)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
def swipe_view(driver, start_point, end_point):
|
||||||
|
is_ele_num = 0
|
||||||
|
if is_appium_element(start_point):
|
||||||
|
is_ele_num += 1
|
||||||
|
|
||||||
|
if is_appium_element(end_point):
|
||||||
|
is_ele_num += 1
|
||||||
|
start_point_coordinate = get_point_coordinate(start_point)
|
||||||
|
# print(start_point_coordinate)
|
||||||
|
end_point_coordinate = get_point_coordinate(end_point)
|
||||||
|
# print(end_point_coordinate)
|
||||||
|
duration = math.sqrt((end_point_coordinate['x'] - start_point_coordinate['x']) ** 2 + (
|
||||||
|
end_point_coordinate['y'] - start_point_coordinate['y']) ** 2) * 5
|
||||||
|
if is_ele_num == 2:
|
||||||
|
driver.scroll(start_point, end_point, duration)
|
||||||
|
else:
|
||||||
|
driver.swipe(start_point_coordinate['x'], start_point_coordinate['y'], end_point_coordinate['x'],
|
||||||
|
end_point_coordinate['y'], duration)
|
||||||
|
|
||||||
|
def swipe_view_time(driver, start_point, end_point, duration):
|
||||||
|
is_ele_num = 0
|
||||||
|
if is_appium_element(start_point):
|
||||||
|
is_ele_num += 1
|
||||||
|
|
||||||
|
if is_appium_element(end_point):
|
||||||
|
is_ele_num += 1
|
||||||
|
start_point_coordinate = get_point_coordinate(start_point)
|
||||||
|
# print(start_point_coordinate)
|
||||||
|
end_point_coordinate = get_point_coordinate(end_point)
|
||||||
|
# print(end_point_coordinate)
|
||||||
|
# duration = math.sqrt((end_point_coordinate['x'] - start_point_coordinate['x']) ** 2 + (
|
||||||
|
# end_point_coordinate['y'] - start_point_coordinate['y']) ** 2) * 5
|
||||||
|
if is_ele_num == 2:
|
||||||
|
driver.scroll(start_point, end_point, duration)
|
||||||
|
else:
|
||||||
|
driver.swipe(start_point_coordinate['x'], start_point_coordinate['y'], end_point_coordinate['x'],
|
||||||
|
end_point_coordinate['y'], duration)
|
||||||
|
|
||||||
|
def is_appium_element(element):
|
||||||
|
import appium
|
||||||
|
if isinstance(element, appium.webdriver.webelement.WebElement):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_point_coordinate(ele):
|
||||||
|
import re
|
||||||
|
coordinate = {}
|
||||||
|
if is_appium_element(ele):
|
||||||
|
temp = ele.get_attribute('bounds')
|
||||||
|
print(temp)
|
||||||
|
searchObj = re.search(r'\[(\d+),(\d+)\]\[(\d+),(\d+)\]', temp)
|
||||||
|
if searchObj:
|
||||||
|
x_1 = int(searchObj.group(1))
|
||||||
|
y_1 = int(searchObj.group(2))
|
||||||
|
x_2 = int(searchObj.group(3))
|
||||||
|
y_2 = int(searchObj.group(4))
|
||||||
|
coordinate['x'] = (x_2 - x_1) / 2 + x_1
|
||||||
|
coordinate['y'] = (y_2 - y_1) / 2 + y_1
|
||||||
|
else:
|
||||||
|
# TODO 抛出异常
|
||||||
|
pass
|
||||||
|
elif isinstance(ele, tuple):
|
||||||
|
coordinate['x'] = ele[0]
|
||||||
|
coordinate['y'] = ele[1]
|
||||||
|
else:
|
||||||
|
# TODO 抛出异常
|
||||||
|
pass
|
||||||
|
return coordinate
|
||||||
|
|
||||||
|
|
||||||
|
def get_zhibiao_button(ele):
|
||||||
|
import re
|
||||||
|
coordinate = {}
|
||||||
|
temp = ele.get_attribute('bounds')
|
||||||
|
print(temp)
|
||||||
|
searchObj = re.search(r'\[(\d+),(\d+)\]\[(\d+),(\d+)\]', temp)
|
||||||
|
if searchObj:
|
||||||
|
x_2 = int(searchObj.group(3))
|
||||||
|
y_2 = int(searchObj.group(4))
|
||||||
|
coordinate['x'] = x_2 / 2
|
||||||
|
coordinate['y'] = y_2 - 100
|
||||||
|
else:
|
||||||
|
# TODO 抛出异常
|
||||||
|
pass
|
||||||
|
print([coordinate['x'], coordinate['y']])
|
||||||
|
return [(coordinate['x'], coordinate['y'])]
|
||||||
|
|
||||||
|
|
||||||
|
def close_open_app(driver, bundld_id, use_key_element=False, key_element=None):
|
||||||
|
"""
|
||||||
|
app关闭重启函数
|
||||||
|
Args:
|
||||||
|
driver: appium驱动
|
||||||
|
bundld_id: 要操作的app包名
|
||||||
|
use_key_element: 是否校验关键元素
|
||||||
|
key_element: 关键元素
|
||||||
|
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
time.sleep(4)
|
||||||
|
if driver.query_app_state(bundld_id) == 4:
|
||||||
|
if use_key_element:
|
||||||
|
if key_element is not None:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
staus = driver.terminate_app(bundld_id, timeout=5000)
|
||||||
|
except:
|
||||||
|
driver.close_app() # 该函数仅能关闭初始化指定的app
|
||||||
|
|
||||||
|
driver.activate_app(bundld_id)
|
||||||
|
if driver.query_app_state(bundld_id) == 4:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
|
@ -0,0 +1,51 @@
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :异步下载操作
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import aiohttp
|
||||||
|
from multiprocessing import Pool
|
||||||
|
|
||||||
|
async def download_link(link):
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(link) as resp:
|
||||||
|
if resp.status == 200:
|
||||||
|
content = await resp.read()
|
||||||
|
# 保存下载内容到本地
|
||||||
|
...
|
||||||
|
|
||||||
|
async def download_links(links):
|
||||||
|
tasks = []
|
||||||
|
for link in links:
|
||||||
|
tasks.append(asyncio.ensure_future(download_link(link)))
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
def download_in_pool(links):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(download_links(links))
|
||||||
|
|
||||||
|
url = 'https://example.com/example.m3u8'
|
||||||
|
r = requests.get(url)
|
||||||
|
if r.status_code == 200:
|
||||||
|
# 解析m3u8文件获取下载链接列表
|
||||||
|
m3u8_content = r.content.decode()
|
||||||
|
download_links = [link.strip() for link in m3u8_content.split('\n') if link.endswith('.ts')]
|
||||||
|
|
||||||
|
# 将下载链接列表按照线程数均分为16份
|
||||||
|
links_list = [download_links[i:i + 16] for i in range(0, len(download_links), 16)]
|
||||||
|
|
||||||
|
# 使用进程池来管理多个进程
|
||||||
|
pool = Pool(processes=16)
|
||||||
|
|
||||||
|
# 在进程池中提交异步下载任务
|
||||||
|
for links in links_list:
|
||||||
|
pool.apply_async(download_in_pool, (links,))
|
||||||
|
|
||||||
|
# 等待所有任务完成
|
||||||
|
pool.close()
|
||||||
|
pool.join()
|
|
@ -0,0 +1,31 @@
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from pywinauto import Desktop
|
||||||
|
|
||||||
|
def upload_files(file_path, *args):
|
||||||
|
"""
|
||||||
|
:param file_path: files path which geometry files in directory
|
||||||
|
:param args: file name about geometry files
|
||||||
|
"""
|
||||||
|
app = Desktop()
|
||||||
|
# select the explorer file popover
|
||||||
|
shon = app["Select Geometry Files"]
|
||||||
|
# accept the one or more files to write into input box
|
||||||
|
for i in args:
|
||||||
|
send_keys('"{}"'.format(i))
|
||||||
|
url_tab = shon["Toolbar3"]
|
||||||
|
url_tab.click()
|
||||||
|
# input url of the geometry files
|
||||||
|
send_keys(file_path)
|
||||||
|
send_keys("{VK_RETURN}")
|
||||||
|
time.sleep(1)
|
||||||
|
shon["打开(O)"].click_input()
|
|
@ -0,0 +1,278 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name: image
|
||||||
|
Description : 颜色识别的工具类
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate: 2023/3/12 10:17
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import collections
|
||||||
|
import tempfile
|
||||||
|
import os, random
|
||||||
|
import time
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
#pillow
|
||||||
|
|
||||||
|
def getColorList():
|
||||||
|
"""
|
||||||
|
颜色范围初始化
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
dict = collections.defaultdict(list)
|
||||||
|
|
||||||
|
# 黑色
|
||||||
|
lower_black = np.array([0, 0, 0])
|
||||||
|
upper_black = np.array([180, 255, 55])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_black)
|
||||||
|
color_list.append(upper_black)
|
||||||
|
dict['black'] = color_list
|
||||||
|
|
||||||
|
# 灰色
|
||||||
|
lower_gray = np.array([0, 0, 55])
|
||||||
|
upper_gray = np.array([180, 43, 220])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_gray)
|
||||||
|
color_list.append(upper_gray)
|
||||||
|
dict['gray'] = color_list
|
||||||
|
|
||||||
|
# 白色
|
||||||
|
lower_white = np.array([0, 0, 221])
|
||||||
|
upper_white = np.array([180, 30, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_white)
|
||||||
|
color_list.append(upper_white)
|
||||||
|
dict['white'] = color_list
|
||||||
|
|
||||||
|
# 红色
|
||||||
|
lower_red = np.array([156, 43, 46])
|
||||||
|
upper_red = np.array([180, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_red)
|
||||||
|
color_list.append(upper_red)
|
||||||
|
dict['red'] = color_list
|
||||||
|
|
||||||
|
# 红色2
|
||||||
|
lower_red = np.array([0, 43, 46])
|
||||||
|
upper_red = np.array([10, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_red)
|
||||||
|
color_list.append(upper_red)
|
||||||
|
dict['red2'] = color_list
|
||||||
|
|
||||||
|
# 橙色
|
||||||
|
lower_orange = np.array([11, 43, 46])
|
||||||
|
upper_orange = np.array([25, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_orange)
|
||||||
|
color_list.append(upper_orange)
|
||||||
|
dict['orange'] = color_list
|
||||||
|
|
||||||
|
# 黄色
|
||||||
|
lower_yellow = np.array([26, 43, 46])
|
||||||
|
upper_yellow = np.array([34, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_yellow)
|
||||||
|
color_list.append(upper_yellow)
|
||||||
|
dict['yellow'] = color_list
|
||||||
|
|
||||||
|
# 绿色
|
||||||
|
lower_green = np.array([35, 43, 46])
|
||||||
|
upper_green = np.array([77, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_green)
|
||||||
|
color_list.append(upper_green)
|
||||||
|
dict['green'] = color_list
|
||||||
|
|
||||||
|
# 青色
|
||||||
|
lower_cyan = np.array([78, 43, 46])
|
||||||
|
upper_cyan = np.array([99, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_cyan)
|
||||||
|
color_list.append(upper_cyan)
|
||||||
|
dict['cyan'] = color_list
|
||||||
|
|
||||||
|
# 蓝色
|
||||||
|
lower_blue = np.array([100, 43, 46])
|
||||||
|
upper_blue = np.array([124, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_blue)
|
||||||
|
color_list.append(upper_blue)
|
||||||
|
dict['blue'] = color_list
|
||||||
|
|
||||||
|
# 紫色
|
||||||
|
lower_purple = np.array([125, 43, 46])
|
||||||
|
upper_purple = np.array([155, 255, 255])
|
||||||
|
color_list = []
|
||||||
|
color_list.append(lower_purple)
|
||||||
|
color_list.append(upper_purple)
|
||||||
|
dict['purple'] = color_list
|
||||||
|
|
||||||
|
return dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_color(image_path, shield_list=None):
|
||||||
|
"""
|
||||||
|
获取指定图片的主体颜色,有且只会返回一种颜色
|
||||||
|
Args:
|
||||||
|
image_path:待处理的图片路径
|
||||||
|
shield_list: 需要屏蔽掉的颜色列表。
|
||||||
|
可选参数有'black'(黑色),'gray'(灰色),'white'(白色),'red'(红色),'red2'(红色2),'orange'(橙色),'yellow'(黄色),
|
||||||
|
'green'(绿色),'cyan'(青色),'blue'(蓝色),'purple'(紫色)
|
||||||
|
|
||||||
|
Returns: 返回指定图片的主体颜色的字符串,例如'black'。如果是纯色图片,且该颜色被屏蔽,则返回None
|
||||||
|
|
||||||
|
"""
|
||||||
|
if shield_list is None:
|
||||||
|
shield_list = []
|
||||||
|
image_frame = cv2.imread(image_path)
|
||||||
|
hsv = cv2.cvtColor(image_frame, cv2.COLOR_BGR2HSV)
|
||||||
|
maxsum = -100
|
||||||
|
color = None
|
||||||
|
color_dict = getColorList()
|
||||||
|
for black_color in shield_list:
|
||||||
|
if black_color in color_dict:
|
||||||
|
color_dict.pop(black_color)
|
||||||
|
tmp_num = random.randint(0, 99)
|
||||||
|
color_dict_len = len(color_dict)
|
||||||
|
same_pic = 0
|
||||||
|
for d in color_dict:
|
||||||
|
mask = cv2.inRange(hsv, color_dict[d][0], color_dict[d][1])
|
||||||
|
# cv2.imwrite(os.path.join(tempfile.gettempdir(), f"{d}_{tmp_num}.jpg"), mask)
|
||||||
|
binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)[1]
|
||||||
|
binary = cv2.dilate(binary, None, iterations=0)
|
||||||
|
cnts, hiera = cv2.findContours(binary.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||||||
|
sum = 0
|
||||||
|
for c in cnts:
|
||||||
|
sum += cv2.contourArea(c)
|
||||||
|
if sum > maxsum:
|
||||||
|
maxsum = sum
|
||||||
|
color = d
|
||||||
|
same_pic = 1
|
||||||
|
elif sum == maxsum:
|
||||||
|
same_pic += 1
|
||||||
|
if same_pic == color_dict_len:
|
||||||
|
color = None
|
||||||
|
|
||||||
|
return color
|
||||||
|
|
||||||
|
|
||||||
|
def get_screenshot_by_element(driver, element):
|
||||||
|
"""
|
||||||
|
获取指定元素的截图(android)
|
||||||
|
Args:
|
||||||
|
driver: appium驱动
|
||||||
|
element: 要获取截图的元素
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# 先截取整个屏幕,存储至系统临时目录下
|
||||||
|
|
||||||
|
TEMP_FILE = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||||
|
driver.get_screenshot_as_file(TEMP_FILE)
|
||||||
|
|
||||||
|
# 获取元素四角坐标
|
||||||
|
location = element.location
|
||||||
|
size = element.size
|
||||||
|
|
||||||
|
# 截取图片
|
||||||
|
TEMP_FILE_2 = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||||
|
cut_image(TEMP_FILE, location["x"], location["y"], location["x"] + size["width"], location["y"] + size["height"],
|
||||||
|
TEMP_FILE_2)
|
||||||
|
return TEMP_FILE_2
|
||||||
|
|
||||||
|
|
||||||
|
def assert_color(driver, element):
|
||||||
|
image_path = get_screenshot_by_element(driver, element)
|
||||||
|
res = get_color(cv2.imread(image_path))
|
||||||
|
if res == 'red' or res == 'red2':
|
||||||
|
return 'red'
|
||||||
|
elif res == 'green':
|
||||||
|
return 'green'
|
||||||
|
|
||||||
|
|
||||||
|
def get_screenshot_by_percent(driver, out_image_path=None, x1=0, y1=0, x2=1, y2=1):
|
||||||
|
"""
|
||||||
|
根据百分比截取屏幕截图
|
||||||
|
Args:
|
||||||
|
driver: appium驱动
|
||||||
|
out_image_path: 截图结果输出路径
|
||||||
|
x1: 所要截取区域左上角坐标的横坐标占屏幕宽度的百分比。0<=x1<=1
|
||||||
|
y1: 所要截取区域左上角坐标的纵坐标占屏幕宽度的百分比。0<=y1<=1
|
||||||
|
x2: 所要截取区域右上角坐标的横坐标占屏幕宽度的百分比。0<=x2<=1
|
||||||
|
y2: 所要截取区域右下角坐标的纵坐标占屏幕宽度的百分比。0<=y2<=1
|
||||||
|
|
||||||
|
Returns:截图结果存放路径
|
||||||
|
|
||||||
|
"""
|
||||||
|
# 先截取整个屏幕,存储至系统临时目录下
|
||||||
|
|
||||||
|
TEMP_FILE = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||||
|
driver.get_screenshot_as_file(TEMP_FILE)
|
||||||
|
|
||||||
|
# 截取图片
|
||||||
|
out_image_path = cut_image(TEMP_FILE, x1, y1, x2, y2, out_image_path, use_percent=True)
|
||||||
|
return out_image_path
|
||||||
|
|
||||||
|
|
||||||
|
def cut_image(input_image_path, x1, y1, x2, y2, out_image_path, use_percent=False):
|
||||||
|
"""
|
||||||
|
图片截取函数
|
||||||
|
Args:
|
||||||
|
input_image_path: 要处理的图片原始路径
|
||||||
|
x1:要截取范围左上角的横坐标或百分比
|
||||||
|
y1:要截取范围左上角的纵坐标或百分比
|
||||||
|
x2:要截取范围右下角的横坐标或百分比
|
||||||
|
y2:要截取范围右下角的纵坐标或百分比
|
||||||
|
out_image_path: 结果输出的图片路径
|
||||||
|
use_percent: 是否启用百分比模式,默认为不启用
|
||||||
|
"""
|
||||||
|
if not out_image_path:
|
||||||
|
out_image_path = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||||
|
image = Image.open(input_image_path) # 读取原始图片
|
||||||
|
if use_percent:
|
||||||
|
size = image.size # 获取图片的尺寸
|
||||||
|
x1 = size[0] * x1
|
||||||
|
y1 = size[1] * y1
|
||||||
|
x2 = size[0] * x2
|
||||||
|
y2 = size[1] * y2
|
||||||
|
box = (x1, y1, x2, y2) # 设定截取区域
|
||||||
|
newImage = image.crop(box) # 进行截取操作
|
||||||
|
newImage.save(out_image_path) # 保存截取结果
|
||||||
|
return out_image_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_color_by_element(driver, element, shield_list=None):
|
||||||
|
"""
|
||||||
|
获取指定元素的主体颜色
|
||||||
|
Args:
|
||||||
|
driver: appium驱动
|
||||||
|
element: 要获取颜色的元素
|
||||||
|
shield_list: 要屏蔽的颜色列表
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return get_color(get_screenshot_by_element(driver, element), shield_list)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# filename = 'ios_h.png'
|
||||||
|
# filename = 'C:\\Users\\viruser.v-desktop\\Desktop\\tmp\\white.png'
|
||||||
|
filename = 'D:\\img\\323232.png'
|
||||||
|
|
||||||
|
# filename = 'ios_l.png'
|
||||||
|
# filename = 'and_h.png'
|
||||||
|
# filename = 'and_l.png'
|
||||||
|
print(get_color(filename, shield_list=['white']))
|
||||||
|
# file_list = ['ios_h.png', 'ios_l.png', 'and_h.png', 'and_l.png']
|
||||||
|
# for i in file_list:
|
||||||
|
# frame = cv2.imread(i)
|
||||||
|
# print(get_color(frame))
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 13:55:01
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc : 免费验证码识别
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪就业辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职就业速成辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:小程序付款 or 支付宝 or 微信
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
from PIL import Image
|
||||||
|
import ddddocr
|
||||||
|
def image_identify(driver, ele, whole_name, crop_name):
|
||||||
|
"""
|
||||||
|
:param driver: 浏览器驱动
|
||||||
|
:param ele: 验证码的元素
|
||||||
|
:param whole_name: 整个页面的截图名字
|
||||||
|
:param crop_name: 页面中对于验证码的抠图名字
|
||||||
|
:return: 返回验证码识别出来的字符串
|
||||||
|
"""
|
||||||
|
driver.save_screenshot(whole_name)
|
||||||
|
left = ele.location['x'] + 220
|
||||||
|
top = ele.location['y'] + 90
|
||||||
|
right = ele.size['width'] + left + 85
|
||||||
|
height = ele.size['height'] + top + 15
|
||||||
|
|
||||||
|
img = Image.open(whole_name).crop((left, top, right, height))
|
||||||
|
img.save(crop_name)
|
||||||
|
|
||||||
|
ocr = ddddocr.DdddOcr()
|
||||||
|
with open(crop_name, 'rb') as f:
|
||||||
|
image = f.read()
|
||||||
|
res = ocr.classification(image)
|
||||||
|
print(res)
|
||||||
|
return res
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import logging
|
||||||
|
from config.conf import cm
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
日志,大家应该都很熟悉这个名词,就是记录代码中的动作。
|
||||||
|
这个文件就是我们用来在自动化测试过程中记录一些操作步骤的。
|
||||||
|
"""
|
||||||
|
class Log:
|
||||||
|
def __init__(self):
|
||||||
|
self.logger = logging.getLogger()
|
||||||
|
if not self.logger.handlers:
|
||||||
|
self.logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
# 创建一个handle写入文件
|
||||||
|
fh = logging.FileHandler(cm.log_file, encoding='utf-8')
|
||||||
|
fh.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 创建一个handle输出到控制台
|
||||||
|
ch = logging.StreamHandler()
|
||||||
|
ch.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# 定义输出的格式
|
||||||
|
formatter = logging.Formatter(self.fmt)
|
||||||
|
fh.setFormatter(formatter)
|
||||||
|
ch.setFormatter(formatter)
|
||||||
|
|
||||||
|
# 添加到handle
|
||||||
|
self.logger.addHandler(fh)
|
||||||
|
self.logger.addHandler(ch)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fmt(self):
|
||||||
|
return '%(levelname)s\t%(asctime)s\t[%(filename)s:%(lineno)d]\t%(message)s'
|
||||||
|
|
||||||
|
log = Log().logger
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
log.info('hello world')
|
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-08-12 19:20:47
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
from page.wps_index.login_page import wps_login
|
||||||
|
|
||||||
|
|
||||||
|
def login(driver, username, password):
|
||||||
|
login1 = wps_login(driver)
|
||||||
|
login1
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import configparser
|
||||||
|
from config.conf import cm
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
读取这个conf.ini配置文件以使用里面的信息
|
||||||
|
###
|
||||||
|
可以看到我们用python内置的configparser模块对config.ini文件进行了读取。
|
||||||
|
对于url值的提取,我使用了高阶语法@property属性值,写法更简单。
|
||||||
|
"""
|
||||||
|
|
||||||
|
HOST = 'HOST'
|
||||||
|
|
||||||
|
|
||||||
|
class ReadConfig(object):
|
||||||
|
"""配置文件"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.config = configparser.RawConfigParser() # 当有%的符号时请使用Raw读取
|
||||||
|
self.config.read(cm.ini_file, encoding='utf-8')
|
||||||
|
|
||||||
|
def _get(self, section, option):
|
||||||
|
"""获取"""
|
||||||
|
return self.config.get(section, option)
|
||||||
|
|
||||||
|
def _set(self, section, option, value):
|
||||||
|
"""更新"""
|
||||||
|
self.config.set(section, option, value)
|
||||||
|
with open(cm.ini_file, 'w') as f:
|
||||||
|
self.config.write(f)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
return self._get(HOST, HOST)
|
||||||
|
|
||||||
|
|
||||||
|
ini = ReadConfig()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(ini.url)
|
|
@ -0,0 +1,45 @@
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.webdriver.chrome.options import Options
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
class ScreenshotUtil:
|
||||||
|
def __init__(self):
|
||||||
|
self.driver = None
|
||||||
|
|
||||||
|
def create_driver(self):
|
||||||
|
options = Options()
|
||||||
|
options.add_argument('--headless')
|
||||||
|
options.add_argument('--disable-gpu')
|
||||||
|
self.driver = webdriver.Chrome(chrome_options=options)
|
||||||
|
|
||||||
|
def take_screenshot(self, name):
|
||||||
|
if not self.driver:
|
||||||
|
self.create_driver()
|
||||||
|
self.driver.get_screenshot_as_file(os.path.join(os.getcwd(), f"{name}.png"))
|
||||||
|
|
||||||
|
def close_driver(self):
|
||||||
|
if self.driver:
|
||||||
|
self.driver.quit()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def screenshot():
|
||||||
|
screenshot_util = ScreenshotUtil()
|
||||||
|
yield screenshot_util
|
||||||
|
screenshot_util.close_driver()
|
||||||
|
|
||||||
|
|
||||||
|
def test_take_screenshot(screenshot):
|
||||||
|
screenshot.take_screenshot("test")
|
||||||
|
assert os.path.isfile(os.path.join(os.getcwd(), "test.png"))
|
|
@ -0,0 +1,36 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import zmail
|
||||||
|
from config.conf import cm
|
||||||
|
|
||||||
|
|
||||||
|
def send_report():
|
||||||
|
"""发送报告"""
|
||||||
|
with open(cm.REPORT_FILE, encoding='utf-8') as f:
|
||||||
|
content_html = f.read()
|
||||||
|
try:
|
||||||
|
mail = {
|
||||||
|
'from': '2211484376@qq.com',
|
||||||
|
'subject': '最新的测试报告邮件',
|
||||||
|
'content_html': content_html,
|
||||||
|
'attachments': [cm.REPORT_FILE, ]
|
||||||
|
}
|
||||||
|
server = zmail.server(*cm.EMAIL_INFO.values())
|
||||||
|
server.send_mail(cm.ADDRESSEE, mail)
|
||||||
|
print("测试邮件发送成功!")
|
||||||
|
except Exception as e:
|
||||||
|
print("Error: 无法发送邮件,{}!", format(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
'''请先在config/conf.py文件设置QQ邮箱的账号和密码'''
|
||||||
|
send_report()
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
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
|
||||||
|
|
||||||
|
"""
|
||||||
|
它使用了WebDriverWait类,可以检测股票数据是否更新,并判断股票是否涨停或跌停:
|
||||||
|
启动Chrome驱动程序并在你的浏览器中加载URL。然后,它将等待10秒钟来检查股票价格是否发生变化。
|
||||||
|
如果股票价格发生变化,则它将打印出涨停或跌停的消息。如果股票价格未发生变化,则测试失败
|
||||||
|
|
||||||
|
"""
|
||||||
|
class RefreshChecker:
|
||||||
|
def __init__(self, url):
|
||||||
|
self.url = url
|
||||||
|
self.driver = webdriver.Chrome()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.driver.get(self.url)
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.driver.quit()
|
||||||
|
|
||||||
|
def get_price(self):
|
||||||
|
# get current price
|
||||||
|
a = self.driver.find_element_by_id('price').text
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
def check_refresh(self, previous_price, timeout=10):
|
||||||
|
WebDriverWait(self.driver, timeout).until(EC.text_to_be_present_in_element((By.ID, 'price'), lambda price: price != previous_price))
|
||||||
|
current_price = self.get_price()
|
||||||
|
price_change = float(current_price) - float(previous_price)
|
||||||
|
if price_change >= 10:
|
||||||
|
print("涨停!")
|
||||||
|
elif price_change <= -10:
|
||||||
|
print("跌停!")
|
||||||
|
# 测似
|
||||||
|
def test_refresh_checker():
|
||||||
|
with RefreshChecker("http://www.baidu.com/stock") as checker:
|
||||||
|
previous_price = checker.get_price()
|
||||||
|
checker.check_refresh(previous_price)
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
|
||||||
|
def timestamp():
|
||||||
|
"""时间戳"""
|
||||||
|
return time.time()
|
||||||
|
|
||||||
|
|
||||||
|
def dt_strftime(fmt="%Y%m"):
|
||||||
|
"""
|
||||||
|
datetime格式化时间
|
||||||
|
:param fmt "%Y%m%d %H%M%S
|
||||||
|
"""
|
||||||
|
return datetime.datetime.now().strftime(fmt)
|
||||||
|
|
||||||
|
|
||||||
|
def sleep(seconds=1.0):
|
||||||
|
"""
|
||||||
|
睡眠时间
|
||||||
|
"""
|
||||||
|
time.sleep(seconds)
|
||||||
|
|
||||||
|
|
||||||
|
def running_time(func):
|
||||||
|
"""函数运行时间"""
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
start = timestamp()
|
||||||
|
res = func(*args, **kwargs)
|
||||||
|
print("校验元素done!用时%.3f秒!" % (timestamp() - start))
|
||||||
|
return res
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
@running_time
|
||||||
|
def aaaaa():
|
||||||
|
"""这里是aaaaa的docstring"""
|
||||||
|
print(dt_strftime("%Y%m%d%H%M%S"))
|
||||||
|
print(aaaaa.__doc__,aaaaa.__name__)
|
||||||
|
aaaaa()
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-26 14:27:52
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
def xb_assert(actual_value, expected_value ):
|
||||||
|
assert actual_value == expected_value, "实际值为: {}, 预期值为: {}".format(actual_value, expected_value)
|
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import os
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from common.times import dt_strftime
|
||||||
|
"""
|
||||||
|
配置文件总是项目中必不可少的部分!
|
||||||
|
将固定不变的信息集中在固定的文件中
|
||||||
|
这个conf文件我模仿了Django的settings.py文件的设置风格,但是又有些许差异
|
||||||
|
author: B站小北 time:2023-04-18
|
||||||
|
"""
|
||||||
|
|
||||||
|
class ConfigManager(object):
|
||||||
|
"""
|
||||||
|
在这个文件中我们可以设置自己的各个目录,也可以查看自己当前的目录。
|
||||||
|
|
||||||
|
遵循了约定:不变的常量名全部大写,函数名小写。看起来整体美观。
|
||||||
|
"""
|
||||||
|
# 项目目录
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
# 页面元素目录
|
||||||
|
ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')
|
||||||
|
|
||||||
|
# 报告文件
|
||||||
|
REPORT_FILE = os.path.join(BASE_DIR, 'report.html')
|
||||||
|
|
||||||
|
# 元素定位的类型
|
||||||
|
LOCATE_MODE = {
|
||||||
|
'css': By.CSS_SELECTOR,
|
||||||
|
'xpath': By.XPATH,
|
||||||
|
'name': By.NAME,
|
||||||
|
'id': By.ID,
|
||||||
|
'class': By.CLASS_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
# 邮件信息
|
||||||
|
EMAIL_INFO = {
|
||||||
|
'username': '2211484376@qq.com', # 切换成你自己的地址
|
||||||
|
'password': 'QQ邮箱授权码',
|
||||||
|
'smtp_host': 'smtp.qq.com',
|
||||||
|
'smtp_port': 465
|
||||||
|
}
|
||||||
|
|
||||||
|
# 收件人
|
||||||
|
ADDRESSEE = [
|
||||||
|
'2211484376@qq.com',
|
||||||
|
]
|
||||||
|
|
||||||
|
# 测试网址
|
||||||
|
BAIDU_URL = "https://www.baidu.com"
|
||||||
|
ZHUIFENG = "https://exam.wzzz.fun"
|
||||||
|
WPS_LOGIN = "https://account.wps.cn/"
|
||||||
|
FILE_UPLOAD = "https://letcode.in/file"
|
||||||
|
@property
|
||||||
|
def log_file(self):
|
||||||
|
"""日志目录"""
|
||||||
|
log_dir = os.path.join(self.BASE_DIR, 'logs')
|
||||||
|
if not os.path.exists(log_dir):
|
||||||
|
os.makedirs(log_dir)
|
||||||
|
return os.path.join(log_dir, '{}.log'.format(dt_strftime()))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ini_file(self):
|
||||||
|
"""配置文件"""
|
||||||
|
ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
|
||||||
|
if not os.path.exists(ini_file):
|
||||||
|
raise FileNotFoundError("配置文件%s不存在!" % ini_file)
|
||||||
|
return ini_file
|
||||||
|
|
||||||
|
|
||||||
|
cm = ConfigManager()
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print(cm.BASE_DIR)
|
|
@ -0,0 +1,135 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import pytest
|
||||||
|
from selenium import webdriver
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description : 产生driver
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
conftest.py测试框架pytest的胶水文件,里面用到了fixture的方法,封装并传递出了driver。
|
||||||
|
test_pytest.fixture 这个实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器。
|
||||||
|
|
||||||
|
管理数据库连接,全局管理我们的driver
|
||||||
|
"""
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session', autouse=True)
|
||||||
|
def drivers():
|
||||||
|
driver = webdriver.Chrome()
|
||||||
|
driver.maximize_window()
|
||||||
|
yield driver
|
||||||
|
driver.quit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# @test_pytest.fixture(scope='session', autouse=True)
|
||||||
|
# def drivers(request):
|
||||||
|
# global driver
|
||||||
|
# if driver is None:
|
||||||
|
# driver = webdriver.Chrome()
|
||||||
|
# driver.maximize_window()
|
||||||
|
#
|
||||||
|
# def fn():
|
||||||
|
# driver.quit()
|
||||||
|
#
|
||||||
|
# request.addfinalizer(fn)
|
||||||
|
# return driver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# @test_pytest.fixture(scope='session', autouse=True)
|
||||||
|
# def drivers():
|
||||||
|
# global driver
|
||||||
|
# option = Options()
|
||||||
|
# # 无头模式
|
||||||
|
# option.add_argument('--headless')
|
||||||
|
# # 沙盒模式运行
|
||||||
|
# option.add_argument('--no-sandbox')
|
||||||
|
# # 大量渲染时候写入/tmp而非/dev/shm
|
||||||
|
# option.add_argument('disable-dev-shm-usage')
|
||||||
|
# # 指定驱动路径
|
||||||
|
# driver = webdriver.Chrome(chrome_options=option)
|
||||||
|
#
|
||||||
|
# yield driver
|
||||||
|
# driver.quit()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# @test_pytest.hookimpl(hookwrapper=True)
|
||||||
|
# def pytest_runtest_makereport(item):
|
||||||
|
# """
|
||||||
|
# 当测试失败的时候,自动截图,展示到html报告中
|
||||||
|
# :param item:
|
||||||
|
# """
|
||||||
|
# pytest_html = item.config.pluginmanager.getplugin('html')
|
||||||
|
# outcome = yield
|
||||||
|
# report = outcome.get_result()
|
||||||
|
# report.description = str(item.function.__doc__)
|
||||||
|
# extra = getattr(report, 'extra', [])
|
||||||
|
#
|
||||||
|
# if report.when == 'call' or report.when == "setup":
|
||||||
|
# xfail = hasattr(report, 'wasxfail')
|
||||||
|
# if (report.skipped and xfail) or (report.failed and not xfail):
|
||||||
|
# file_name = report.nodeid.replace("::", "_") + ".png"
|
||||||
|
# screen_img = _capture_screenshot()
|
||||||
|
# if file_name:
|
||||||
|
# html = '<div><img src="data:image/png;base64,%s" alt="screenshot" style="width:1024px;height:768px;" ' \
|
||||||
|
# 'onclick="window.open(this.src)" align="right"/></div>' % screen_img
|
||||||
|
# extra.append(pytest_html.extras.html(html))
|
||||||
|
# report.extra = extra
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def pytest_html_results_table_header(cells):
|
||||||
|
# cells.insert(1, html.th('用例名称'))
|
||||||
|
# cells.insert(2, html.th('Test_nodeid'))
|
||||||
|
# cells.pop(2)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def pytest_html_results_table_row(report, cells):
|
||||||
|
# cells.insert(1, html.td(report.description))
|
||||||
|
# cells.insert(2, html.td(report.nodeid))
|
||||||
|
# cells.pop(2)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def pytest_html_results_table_html(report, data):
|
||||||
|
# if report.passed:
|
||||||
|
# del data[:]
|
||||||
|
# data.append(html.div('通过的用例未捕获日志输出.', class_='empty log'))
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# def _capture_screenshot():
|
||||||
|
# '''
|
||||||
|
# 截图保存为base64
|
||||||
|
# :return:
|
||||||
|
# '''
|
||||||
|
# return driver.get_screenshot_as_base64()
|
|
@ -0,0 +1,17 @@
|
||||||
|
username,password
|
||||||
|
user1434sfdsvfdsfffffffffffg,pass1sdgggggggggggggggggggggggg
|
||||||
|
user2sgdddddddddddddddddddddd,pass2sdggggggggggggggggggggggf
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
||||||
|
wzzr43ferde4rf4erft4erft4ertf,1234543tr4ertfergvf34terferfgt34t
|
||||||
|
user143t34trfrdfvdfvgefrferf,pass1ertg34tgervgfrdgvergergfgrg
|
|
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,88 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name: basePage
|
||||||
|
Description : Python descriptor
|
||||||
|
Author : beige
|
||||||
|
CreateDate: 2023/03/19 21:36
|
||||||
|
-------------------------------------------------
|
||||||
|
功能:1、可以轻松实现元素定位
|
||||||
|
2、还可以实现在某个元素输入字符串
|
||||||
|
"""
|
||||||
|
from selenium import webdriver
|
||||||
|
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
||||||
|
from selenium.webdriver.common.by import By
|
||||||
|
from selenium.webdriver.support.ui import WebDriverWait
|
||||||
|
|
||||||
|
# Map PageElement constructor arguments to webdriver locator enums
|
||||||
|
_LOCATOR_MAP = {
|
||||||
|
'xpath': By.XPATH,
|
||||||
|
'id': By.ID,
|
||||||
|
'tag_name': By.TAG_NAME,
|
||||||
|
'name': By.NAME,
|
||||||
|
'css': By.CSS_SELECTOR,
|
||||||
|
'class1':By.CLASS_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
class PageObject(object):
|
||||||
|
"""
|
||||||
|
接收driver,为了让driver后续完全脱手,再也不接触driver而写,让测试者能够拜托driver的繁琐操作。
|
||||||
|
Page Object pattern.
|
||||||
|
:param webdriver: `selenium.webdriver.WebDriver`
|
||||||
|
Selenium webdriver instance
|
||||||
|
:param root_uri: `str`
|
||||||
|
Root URI to base any calls to the ``PageObject.get`` method. If not defined
|
||||||
|
in the constructor it will try and look it from the webdriver object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, webdriver: object):
|
||||||
|
"""接收driver,为了让driver后续完全脱手,再也不接触driver而写,让测试者能够拜托driver的繁琐操作。"""
|
||||||
|
self.w = webdriver
|
||||||
|
|
||||||
|
class PageElement(object):
|
||||||
|
"""Page Element descriptor.
|
||||||
|
:param xpath: `str`
|
||||||
|
Use this xpath locator
|
||||||
|
elem1 = PageElement(css='div.myclass')
|
||||||
|
elem2 = PageElement(id='foo')
|
||||||
|
Page Elements act as property descriptors for their Page Object, you can get
|
||||||
|
and set them as normal attributes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, context=False, **kwargs):
|
||||||
|
"""处理传进来的元素定位键值对,让(id='kw')变成(By.id, 'kw')"""
|
||||||
|
if not kwargs:
|
||||||
|
raise ValueError("Please specify a locator")
|
||||||
|
if len(kwargs) > 1:
|
||||||
|
raise ValueError("Please specify only one locator")
|
||||||
|
k, v = next(iter(kwargs.items())) # 使用了迭代器,生成器来让(id='kw')变成By.id, 'kw'两个单独的参数
|
||||||
|
self.locator = (_LOCATOR_MAP[k], v)
|
||||||
|
self.has_context = bool(context)
|
||||||
|
|
||||||
|
def __get__(self, instance, owner, context=None):
|
||||||
|
"""实现元素定位find_element()"""
|
||||||
|
if not instance:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not context and self.has_context:
|
||||||
|
return lambda ctx: self.__get__(instance, owner, context=ctx)
|
||||||
|
|
||||||
|
if not context:
|
||||||
|
context = instance.w
|
||||||
|
|
||||||
|
return WebDriverWait(context, 5, 1).until(lambda x: x.find_element(*self.locator))
|
||||||
|
|
||||||
|
def __set__(self, instance, value):
|
||||||
|
"""实现往元素中写入东西,send_keys()"""
|
||||||
|
if self.has_context:
|
||||||
|
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
|
||||||
|
elem = self.__get__(instance, instance.__class__)
|
||||||
|
if not elem:
|
||||||
|
raise ValueError("Can't set value, element not found")
|
||||||
|
elem.send_keys(value)
|
||||||
|
|
||||||
|
|
||||||
|
# Backwards compatibility with previous versions that used factory methods
|
||||||
|
page_element = PageElement
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-08-15 18:42:37
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪就业辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职就业辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP就业速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:官方小程序付款 or 微信 or 支付宝
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
|
||||||
|
from page.basePage import *
|
||||||
|
|
||||||
|
class FileUpload(PageObject):
|
||||||
|
file_choose = PageElement(css='.file-label')
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def click_file_choose(self):
|
||||||
|
"""点击搜索"""
|
||||||
|
return self.file_choose.click()
|
|
@ -0,0 +1,33 @@
|
||||||
|
from page.basePage import PageObject, PageElement
|
||||||
|
from page.basePage import *
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
在平时中我们应该养成写注释的习惯,因为过一段时间后,没有注释,代码读起来很费劲。
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class zhuifeng_index_page(PageObject):
|
||||||
|
input_account = PageElement(xpath='/html/body/section/main/div/div[2]/div/form/div[1]/div/div/input')
|
||||||
|
input_password = PageElement(xpath='/html/body/section/main/div/div[2]/div/form/div[2]/div/div/input')
|
||||||
|
auto_code = PageElement(xpath='/html/body/section/main/div/div[2]/div/form/div[3]/div/div/input')
|
||||||
|
log_in_button = PageElement(xpath='/html/body/section/main/div/div[2]/div/form/div[4]/div/button[1]')
|
||||||
|
image = PageElement(id='code')
|
||||||
|
image_code = PageElement(xpath='/html/body/section/main/div/div[2]/div/form/div[3]/div/div/input')
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def click_log_in_button(self):
|
||||||
|
"""点击搜索"""
|
||||||
|
return self.log_in_button.click()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
[pytest]
|
||||||
|
;addopts:配置命令行参数,用空格进行分隔
|
||||||
|
;可执行标记为mark的对应用例,用or表示标记为demo或者smoke的用例都会执行
|
||||||
|
addopts =
|
||||||
|
-vs
|
||||||
|
--alluredir=./reports/
|
||||||
|
--clean-alluredir
|
||||||
|
-m "smoke"
|
||||||
|
-n 0
|
||||||
|
--reruns=0
|
||||||
|
|
||||||
|
;注册 mark 标记
|
||||||
|
markers =
|
||||||
|
smoke: marks tests as smoke
|
||||||
|
test: marks tests as test
|
||||||
|
testNow: marks tests as testNow
|
||||||
|
;执行的时候使用 pytest -m smoke
|
||||||
|
|
||||||
|
minversion = 5.0
|
||||||
|
|
||||||
|
;测试用例的路径,可自己配置,
|
||||||
|
;../pytestproject为上一层的pytestproject文件夹
|
||||||
|
;./testcase为pytest.ini当前目录下的同级文件夹
|
||||||
|
;改变用例的查找路径规则,当前目录的testcase文件夹下的所有
|
||||||
|
testpaths =./testcases/
|
||||||
|
|
||||||
|
;模块名的规则,配置测试搜索的模块文件名称
|
||||||
|
python_files = test*.py
|
||||||
|
|
||||||
|
;类名的规则,配置测试搜索的测试类名
|
||||||
|
python_classes = Test*
|
||||||
|
|
||||||
|
;方法名的规则,配置测试搜索的测试函数名
|
||||||
|
python_functions = test
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "66ae6d33-e955-4397-927c-44e95e90a7e3", "children": ["7f19c6f7-a80f-4b70-985a-7cfcd5e63804", "ee15855b-c6d9-4be8-b5ff-f67ef1bdad75", "4e339847-f374-4691-9f96-6b87e2d51832"], "befores": [{"name": "drivers", "status": "passed", "start": 1691998099297, "stop": 1691998101160}], "afters": [{"name": "drivers::0", "status": "passed", "start": 1691998116026, "stop": 1691998118116}], "start": 1691998099297, "stop": 1691998118116}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "5fc06f2f-c6ae-4e11-ae8f-f25706efe8d2", "befores": [{"name": "username", "status": "passed", "start": 1691998105893, "stop": 1691998105893}], "start": 1691998105893, "stop": 1691998115417}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "fcf82d15-9117-41ea-9be3-09f41dbd4ca7", "children": ["7f19c6f7-a80f-4b70-985a-7cfcd5e63804"], "befores": [{"name": "open_baidu", "status": "passed", "start": 1691998101161, "stop": 1691998105892}], "afters": [{"name": "open_baidu::0", "status": "passed", "start": 1691998115418, "stop": 1691998115418}], "start": 1691998101160, "stop": 1691998115418}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "506fc813-3192-40a1-88e1-52788dbbc862", "befores": [{"name": "username", "status": "passed", "start": 1691998115751, "stop": 1691998115752}], "start": 1691998115751, "stop": 1691998115941}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
{"name": "test_001[user1-pass1]", "status": "passed", "parameters": [{"name": "username", "value": "'user1'"}, {"name": "password", "value": "'pass1'"}], "start": 1691998105893, "stop": 1691998115416, "uuid": "7f19c6f7-a80f-4b70-985a-7cfcd5e63804", "historyId": "7447b017eda5d8972c74406bfcfd1dba", "testCaseId": "f4ef65b043d05db61048415b9c5a1413", "fullName": "testcases.zhuifeng_tc.test_ddt_zhuifeng.TestSearch2#test_001", "labels": [{"name": "tag", "value": "smoke"}, {"name": "parentSuite", "value": "testcases.zhuifeng_tc"}, {"name": "suite", "value": "test_ddt_zhuifeng"}, {"name": "subSuite", "value": "TestSearch2"}, {"name": "host", "value": "LAPTOP-2RGLO47J"}, {"name": "thread", "value": "68708-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "testcases.zhuifeng_tc.test_ddt_zhuifeng"}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "aa385fe0-fcef-4dfd-95d5-deadc8129ca0", "children": ["4e339847-f374-4691-9f96-6b87e2d51832"], "befores": [{"name": "open_baidu", "status": "broken", "statusDetails": {"message": "selenium.common.exceptions.NoSuchWindowException: Message: no such window: target window already closed\nfrom unknown error: web view not found\n (Session info: chrome=114.0.5735.199)\nStacktrace:\nBacktrace:\n\tGetHandleVerifier [0x0038A813+48355]\n\t(No symbol) [0x0031C4B1]\n\t(No symbol) [0x00225358]\n\t(No symbol) [0x0020D293]\n\t(No symbol) [0x0026E37B]\n\t(No symbol) [0x0027C473]\n\t(No symbol) [0x0026A536]\n\t(No symbol) [0x002482DC]\n\t(No symbol) [0x002493DD]\n\tGetHandleVerifier [0x005EAABD+2539405]\n\tGetHandleVerifier [0x0062A78F+2800735]\n\tGetHandleVerifier [0x0062456C+2775612]\n\tGetHandleVerifier [0x004151E0+616112]\n\t(No symbol) [0x00325F8C]\n\t(No symbol) [0x00322328]\n\t(No symbol) [0x0032240B]\n\t(No symbol) [0x00314FF7]\n\tBaseThreadInitThunk [0x764B00C9+25]\n\tRtlGetAppContainerNamedObjectPath [0x77507B1E+286]\n\tRtlGetAppContainerNamedObjectPath [0x77507AEE+238]\n\n", "trace": " File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\pluggy\\_callers.py\", line 39, in _multicall\n res = hook_impl.function(*args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\_pytest\\fixtures.py\", line 1130, in pytest_fixture_setup\n result = call_fixture_func(fixturefunc, request, kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\_pytest\\fixtures.py\", line 902, in call_fixture_func\n fixture_result = next(generator)\n ^^^^^^^^^^^^^^^\n File \"H:\\Develop\\Python\\Selenium_UI_Project_2023_08_14\\testcases\\zhuifeng_tc\\test_ddt_zhuifeng.py\", line 33, in open_baidu\n drivers.get(ConfigManager.ZHUIFENG)\n File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py\", line 449, in get\n self.execute(Command.GET, {\"url\": url})\n File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py\", line 440, in execute\n self.error_handler.check_response(response)\n File \"H:\\Develop\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\errorhandler.py\", line 245, in check_response\n raise exception_class(message, screen, stacktrace)\n"}, "start": 1691998115957, "stop": 1691998115958}], "start": 1691998115957, "stop": 1691998116024}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "7597ef3d-c261-44de-85ab-4859306a7342", "befores": [{"name": "password", "status": "passed", "start": 1691998105893, "stop": 1691998105893}], "start": 1691998105893, "stop": 1691998115416}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "0d046b0d-e722-45bd-96de-41477187d81d", "children": ["ee15855b-c6d9-4be8-b5ff-f67ef1bdad75"], "befores": [{"name": "open_baidu", "status": "passed", "start": 1691998115423, "stop": 1691998115750}], "afters": [{"name": "open_baidu::0", "status": "passed", "start": 1691998115942, "stop": 1691998115942}], "start": 1691998115423, "stop": 1691998115942}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "f32cd291-f80c-4b2e-a1d4-3fa05d9d7fea", "befores": [{"name": "password", "status": "passed", "start": 1691998115752, "stop": 1691998115752}], "start": 1691998115752, "stop": 1691998115939}
|
Binary file not shown.
After Width: | Height: | Size: 338 KiB |
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 13:54:50
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pass
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "ce0eeefd-2a2a-4018-a3b9-718cd422d8c6", "children": ["68fc0bc4-6ad8-49dc-924c-d3a871a19290"], "befores": [{"name": "drivers", "status": "passed", "start": 1692107307725, "stop": 1692107319283}], "afters": [{"name": "drivers::0", "status": "passed", "start": 1692107424127, "stop": 1692107428670}], "start": 1692107307725, "stop": 1692107428670}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "7c866e15-5cf4-401e-a2c7-0444227fcd47", "children": ["68fc0bc4-6ad8-49dc-924c-d3a871a19290"], "befores": [{"name": "open_baidu", "status": "passed", "start": 1692107319284, "stop": 1692107324782}], "afters": [{"name": "open_baidu::0", "status": "passed", "start": 1692107424126, "stop": 1692107424126}], "start": 1692107319284, "stop": 1692107424126}
|
|
@ -0,0 +1 @@
|
||||||
|
{"name": "test_001[wzz-12345]", "status": "passed", "parameters": [{"name": "username", "value": "'wzz'"}, {"name": "password", "value": "'12345'"}], "start": 1692107324912, "stop": 1692107424124, "uuid": "68fc0bc4-6ad8-49dc-924c-d3a871a19290", "historyId": "d590c7043674851a28364ae332272855", "testCaseId": "75ce6b87312d044f17edfe42bfb0fde7", "fullName": "testcases.zhuifeng_tc.test_ddt_zhuifeng.TestSearch#test_001", "labels": [{"name": "tag", "value": "smoke"}, {"name": "parentSuite", "value": "testcases.zhuifeng_tc"}, {"name": "suite", "value": "test_ddt_zhuifeng"}, {"name": "subSuite", "value": "TestSearch"}, {"name": "host", "value": "LAPTOP-2RGLO47J"}, {"name": "thread", "value": "14440-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "testcases.zhuifeng_tc.test_ddt_zhuifeng"}]}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "7f2b1f3e-3d70-4378-8776-469aef9249b0", "befores": [{"name": "password", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424124}
|
|
@ -0,0 +1 @@
|
||||||
|
{"uuid": "1bcd466c-4cff-414e-b378-8b136d4b2a10", "befores": [{"name": "username", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424126}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 13:55:01
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
from common.image_identify import image_identify
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TestSearch:
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(self, drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
@pytest.mark.smoke
|
||||||
|
@pytest.mark.parametrize('username, password', [
|
||||||
|
('wzz', '12345')
|
||||||
|
])
|
||||||
|
def test_001(self, drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.image_code = image_identify(drivers, zhufeng.image, 'whole_pic.png', 'crop_pic.png')
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(['vs', 'testcases/test_pytest/test_search_baidu_index.py'])
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 14:04:29
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
def read_csv_file(file_path):
|
||||||
|
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||||
|
with open(file_path, 'r', newline='') as file:
|
||||||
|
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||||
|
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||||
|
yield row['username'], row['password']
|
||||||
|
@pytest.mark.smoke
|
||||||
|
@pytest.mark.parametrize('username, password', read_csv_file(r'H:\Develop\Python\Selenium_UI_Project\data\data.csv'))
|
||||||
|
def test_001(drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||||
|
|
||||||
|
|
||||||
|
# if __name__ == '__main__':
|
||||||
|
# pytest.main(['--alluredir', './reports', 'vs', 'testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py'])
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 14:04:29
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
def read_csv_file(file_path):
|
||||||
|
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||||
|
with open(file_path, 'r', newline='') as file:
|
||||||
|
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||||
|
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||||
|
yield row['username'], row['password']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('username, password', read_csv_file(r'H:\Develop\Python\Selenium_UI_Project\data\data.csv'))
|
||||||
|
def test_001(drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 14:04:29
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
def read_csv_file(file_path):
|
||||||
|
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||||
|
with open(file_path, 'r', newline='') as file:
|
||||||
|
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||||
|
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||||
|
yield row['username'], row['password']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('username, password', read_csv_file(r'H:\Develop\Python\Selenium_UI_Project\data\data.csv'))
|
||||||
|
def test_001(drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(['--alluredir', './reports', 'vs', 'testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file3.py'])
|
||||||
|
|
||||||
|
# t1 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py"],))
|
||||||
|
# t2 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng.py"],))
|
||||||
|
# t3 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_zhuifeng_system.py"],))
|
||||||
|
#
|
||||||
|
# t1.start()
|
||||||
|
# t2.start()
|
||||||
|
# t3.start()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# t1.join()
|
||||||
|
# t2.join()
|
||||||
|
# t3.join()
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 14:04:29
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
def read_csv_file(file_path):
|
||||||
|
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||||
|
with open(file_path, 'r', newline='') as file:
|
||||||
|
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||||
|
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||||
|
yield row['username'], row['password']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('username, password', read_csv_file(r'H:\Develop\Python\Selenium_UI_Project\data\data.csv'))
|
||||||
|
def test_001(drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(['--alluredir', './reports', 'vs', 'testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file4.py'])
|
||||||
|
|
||||||
|
# t1 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py"],))
|
||||||
|
# t2 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng.py"],))
|
||||||
|
# t3 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_zhuifeng_system.py"],))
|
||||||
|
#
|
||||||
|
# t1.start()
|
||||||
|
# t2.start()
|
||||||
|
# t3.start()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# t1.join()
|
||||||
|
# t2.join()
|
||||||
|
# t3.join()
|
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 14:04:29
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
import csv
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(drivers):
|
||||||
|
"""打开百度"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
def read_csv_file(file_path):
|
||||||
|
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||||
|
with open(file_path, 'r', newline='') as file:
|
||||||
|
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||||
|
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||||
|
yield row['username'], row['password']
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('username, password', read_csv_file(r'H:\Develop\Python\Selenium_UI_Project_2023_08_14\data\data.csv'))
|
||||||
|
def test_001(drivers, username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
# zhufeng.log_in_button.click()
|
||||||
|
zhufeng.click_log_in_button
|
||||||
|
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(['--alluredir', './reports', 'vs', 'testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file5.py'])
|
||||||
|
|
||||||
|
# t1 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py"],))
|
||||||
|
# t2 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_ddt_zhuifeng.py"],))
|
||||||
|
# t3 = threading.Thread(target=test_pytest.main,
|
||||||
|
# args=(["-v", "-s", "testcases/zhuifeng_tc/test_zhuifeng_system.py"],))
|
||||||
|
#
|
||||||
|
# t1.start()
|
||||||
|
# t2.start()
|
||||||
|
# t3.start()
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# t1.join()
|
||||||
|
# t2.join()
|
||||||
|
# t3.join()
|
|
@ -0,0 +1,53 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
# ==================================================
|
||||||
|
# @Time : 2023-06-23 13:55:01
|
||||||
|
# @Author : 小北
|
||||||
|
# @微信:xiaobei_upup
|
||||||
|
# @Email : 2211484376@qq.com
|
||||||
|
# @QQ群:585971269
|
||||||
|
# @微信群:可加我微信拉你
|
||||||
|
# @Site : 苏州
|
||||||
|
# @Desc :
|
||||||
|
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||||
|
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||||
|
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||||
|
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||||
|
# ==================================================
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.file_upload_pages import FileUpload
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
from pywinauto import Desktop
|
||||||
|
from common.image_identify import image_identify
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TestFileUpload:
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_file_upload(self, drivers):
|
||||||
|
"""打开文件上传网址"""
|
||||||
|
drivers.get(ConfigManager.FILE_UPLOAD)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
@pytest.mark.smoke
|
||||||
|
def test_001(self, drivers):
|
||||||
|
file = FileUpload(drivers)
|
||||||
|
file.click_file_choose
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
app = Desktop()
|
||||||
|
dialog = app['打开']
|
||||||
|
# 根据名字找到弹出窗口
|
||||||
|
dialog["Edit"].type_keys('1.jpg')
|
||||||
|
# 在弹出的框中输入相关的值。
|
||||||
|
dialog["Button"].click()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
pytest.main(['vs', 'testcases/test_pytest/test_file_upload.py'])
|
|
@ -0,0 +1,54 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
-------------------------------------------------
|
||||||
|
File Name:
|
||||||
|
Description :
|
||||||
|
Author : xiaobei
|
||||||
|
CreateDate:
|
||||||
|
wechat:xiaobei_upup
|
||||||
|
-------------------------------------------------
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||||
|
from config.conf import ConfigManager
|
||||||
|
import time
|
||||||
|
|
||||||
|
"""
|
||||||
|
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TestSearch2:
|
||||||
|
@pytest.fixture(scope='function', autouse=True)
|
||||||
|
def open_baidu(self, drivers):
|
||||||
|
"""打开"""
|
||||||
|
drivers.get(ConfigManager.ZHUIFENG)
|
||||||
|
yield
|
||||||
|
print("后置")
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('username, password', [
|
||||||
|
('user1', 'pass1'),
|
||||||
|
('user2', 'pass2'),
|
||||||
|
('user3', 'pass3')
|
||||||
|
])
|
||||||
|
def test_001(self, drivers,username, password):
|
||||||
|
zhufeng = zhuifeng_index_page(drivers)
|
||||||
|
zhufeng.input_account = username
|
||||||
|
zhufeng.input_password = password
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
|
||||||
|
# @allure.step("操作步骤2")
|
||||||
|
# def test_002(self, drivers):
|
||||||
|
# baidu = baidu_index_page(drivers)
|
||||||
|
# baidu.search_frame.send_keys('阿里巴巴')
|
||||||
|
#
|
||||||
|
# baidu.click_search
|
||||||
|
# webdriver = WebPage(drivers)
|
||||||
|
# webdriver.refresh()
|
||||||
|
# # print(webdriver.get_source)
|
||||||
|
# assert baidu.search_button
|
||||||
|
# # log.info()
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 218 KiB |
Loading…
Reference in New Issue