新增用例:新建疑修

This commit is contained in:
floraachy 2023-11-22 17:01:04 +08:00
parent 6caa52586b
commit b8716da798
13 changed files with 226 additions and 88 deletions

28
case_data/issue_data.py Normal file
View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# @Time : 2023/11/22 14:48
# @Author : floraachy
# @File : issue_data
# @Software: PyCharm
# @Desc:
case_common = {
"allure_epic": "GitLink",
"allure_feature": "开源项目模块",
}
# 登录成功
new_issue_success = {
"allure_story": "疑修",
"cases":
[
{"title": "登录状态下,在测试仓库新建疑修",
"run": True,
"severity": "critical",
"project_url": "${project_url}",
"issue_title": "Auto Test ${generate_name()}",
"issue_desc": "${generate_name()}",
"issue_attach": "gitlinklogo2.png",
}
]
}

View File

@ -17,10 +17,10 @@ login_pop_success = {
"cases":
[
{"title": "弹窗登录: 正确用户名和密码登录成功",
"user": "${login}",
"password": "${password}",
"run": True,
"severity": "critical",
"user": "${login}",
"password": "${password}",
"expected_url": "/explore",
"expected_user": "${login}"
}
@ -32,10 +32,10 @@ login_page_success = {
"cases":
[
{"title": "网页登录: 正确用户名和密码登录成功",
"user": "${login}",
"password": "${password}",
"run": True,
"severity": "critical",
"user": "${login}",
"password": "${password}",
"expected_url": "/${login}",
"expected_user": "${login}"
}

View File

@ -7,6 +7,7 @@
# 标准库导入
import os
from typing import Union
# 第三方库导入
import allure
import time
@ -114,6 +115,15 @@ class BasePage:
logger.info(f"获取当前页面的路由:{url}")
return url
@allure.step("获取当前网页标题")
def get_page_title(self):
"""
获取网页标题
"""
page_title = self.driver.title
logger.info(f"获取当前页面的网页标题:{page_title}")
return page_title
@allure.step("____iframe切换- {reference}")
def switch_to_frame(self, reference=None, timeout=10, poll=0.2):
"""
@ -332,32 +342,41 @@ class BasePage:
allure.attach.file(source=file_path, attachment_type=allure.attachment_type.PNG)
@allure.step("____执行js脚本 - {js}")
def execute_js(self, js):
def execute_js(self, js, *args):
"""
执行javascript脚本
js: 元组形式参数
"""
try:
self.driver.execute_script(js)
self.driver.execute_script(js, *args)
logger.info(f"执行js脚本成功:{js}")
except Exception as e:
logger.error(f"执行js脚本失败:{js}, 报错:{e}")
raise e
@allure.step("____使用pyautogui上传文件 - {files}")
def upload_file_pyautogui(self, files: list):
def upload_file_pyautogui(self, files: Union[str, list]):
"""
使用pyautogui来上传
缺点只能选择一个文件路径中有中文会出问题
优点跨平台Linux, macwindows都可以
安装pip install pyautogui -i https://mirrors.aliyun.com/pypi/simple/
param files: 文件绝对路径,支持传数组
:param files: 文件绝对路径, 支持传字符串或数组
"""
logger.info(f"使用pyautogui上传文件 - {files}")
for file in files:
logger.info(f"使用pyautogui上传文件 - {file}")
# 上传文件之前,确保打开选择文件框,确保鼠标聚焦在文件名框。增加一定等待时间,避免文件名键入错误
time.sleep(2)
if isinstance(files, str):
# 上传文件
pyautogui.write(file)
pyautogui.write(files)
# 点击回车
pyautogui.press("enter", 2)
if isinstance(files, list):
for file in files:
# 上传文件
pyautogui.write(file)
# 点击回车
pyautogui.press("enter", 2)

View File

@ -318,7 +318,7 @@ class DataHandle:
should_eval = 0
for key, value in keys.items(): # 遍历字典替换
obj = obj.replace(key, value[0])
if not isinstance(source[value[1]], str):
if source.get(value[1]) and not isinstance(source[value[1]], str):
should_eval = 1
if should_eval == 1:
obj = self.eval_data(obj)
@ -514,7 +514,8 @@ if __name__ == '__main__':
print("-----------测试场景17---------------------")
data_17 = {
"winner_id": "${winner_id}",
"user_id": "${user_id}"
"user_id": "${user_id}",
"time": "${generate_time}"
}
source = {
"winner_id": "1,2,4",

View File

@ -51,7 +51,7 @@ class RunConfig:
# 浏览器类型(不需要修改)
driver_type = None
# 浏览器驱动对象(不需要修改)
drivers = None
driver = None
# 失败重跑次数
rerun = 0

View File

@ -39,22 +39,21 @@ def pytest_runtest_makereport(item, call):
xfail = hasattr(report, "wasxfail")
if (report.skipped and xfail) or (report.failed and not xfail):
# 截图
drivers = RunConfig.drivers
if drivers:
for driver in drivers:
logger.debug(f"{driver} 开始进行截图操作......")
# 创建不同浏览器驱动保存截图的目录
driver_dir = os.path.join(IMG_DIR, str(driver).split(".")[2])
os.makedirs(driver_dir, exist_ok=True)
parameters = item.callspec.params["case"]
# logger.debug(f"测试用例参数:{type(parameters)} {parameters}")
file_name = FakerData.remove_special_characters(
target=parameters.get("title", "")) + "_" + datetime.now().strftime(
"%Y-%m-%d %H_%M_%S") + ".png"
BasePage(driver=driver).screenshot(path=driver_dir, filename=file_name)
img_path = os.path.join(driver_dir, file_name)
if img_path:
allure_step(step_title="点击查看失败截图......", content=report.nodeid, source=img_path)
if RunConfig.driver:
driver = RunConfig.driver
logger.debug(f"{driver} 开始进行截图操作......")
# 创建不同浏览器驱动保存截图的目录
driver_dir = os.path.join(IMG_DIR, str(driver).split(".")[2])
os.makedirs(driver_dir, exist_ok=True)
parameters = item.callspec.params["case"]
# logger.debug(f"测试用例参数:{type(parameters)} {parameters}")
file_name = FakerData.remove_special_characters(
target=parameters.get("title", "")) + "_" + datetime.now().strftime(
"%Y-%m-%d %H_%M_%S") + ".png"
BasePage(driver=driver).screenshot(path=driver_dir, filename=file_name)
img_path = os.path.join(driver_dir, file_name)
if img_path:
allure_step(step_title="点击查看失败截图......", content=report.nodeid, source=img_path)
def pytest_terminal_summary(terminalreporter, config):

View File

@ -18,6 +18,7 @@ class RepoCommonPage(BasePage):
def open_site(self, host, project_url):
"""访问项目详情页"""
full_url = url_handle(host, project_url)
print(f"这里的页面是什么:{full_url}")
self.visit(full_url)
return full_url

View File

@ -7,39 +7,59 @@
# 标准库导入
import os
import time
# 第三方库导入
from selenium.webdriver.common.by import By
# 本地应用/模块导入
from case_utils.base_page import BasePage
from case_utils.allure_handle import allure_step
from case_utils.tools import url_handle
class RepoIssuePage(BasePage):
def open_site(self, host):
"""
访问仓库疑修页面
"""
full_url = url_handle(host, "/issues")
self.visit(full_url)
def click_create_issue_button(self):
"""
点击"创建疑修"按钮
"""
self.click((By.XPATH, "//a[text()='创建疑修']"))
time.sleep(3)
def input_issue_title(self, issue_title: str):
"""
输入疑修标题
"""
self.input((By.ID, "subject"), text=issue_title)
time.sleep(1)
def input_issue_desc(self, issue_desc: str):
"""
输入疑修内容
"""
elem = self.driver.find_element(By.XPATH, "//textarea/following::div[contains(@class, 'CodeMirror-wrap')]")
self.execute_js('''([elem, content]) => elem.CodeMirror.setValue(content);''',
[elem, issue_desc])
self.execute_js("arguments[0].CodeMirror.setValue(arguments[1]);", elem, issue_desc)
time.sleep(1)
def upload_issue_attach(self, issue_file):
"""
上传疑修附件
"""
self.click(locator=(By.XPATH, "//p[text()='拖动文件或点击此处上传']/parent::div/preceding-sibling::input"))
time.sleep(1)
self.upload_file_pyautogui(files=issue_file)
time.sleep(1)
def submit_issue(self):
"""
点击"创建"按钮提交表单校验进行疑修创建
"""
self.click((By.XPATH, "//span[text()='创 建']/parent::button"))
time.sleep(3)
def get_issue_success_text(self):
"""
@ -53,16 +73,16 @@ class RepoIssuePage(BasePage):
"""
return self.get_text((By.XPATH, "//div[@class='detailtitle']/div/p"))
def check_issue_desc(self):
def get_issue_desc(self):
"""
获取易修内容
"""
return self.get_text((By.XPATH, "//div[@class='descPanel']/div/p"))
def get_issue_attachments(self, files):
def get_issue_attachments(self):
"""
检查易修附件
"""
actual_issue_files = self.get_all_elements_text(
locator="//div[contains(@class, 'attachment-list-div')]//span[1]")
return [os.path.basename(file_path) for file_path in files]
(By.XPATH, "//div[contains(@class, 'attachment-list-div')]//span[1]"))
return [os.path.basename(file_path) for file_path in actual_issue_files]

2
run.py
View File

@ -93,7 +93,7 @@ if __name__ == '__main__':
help="是否生成allure html report支持如下类型yes, no")
parser.add_argument("-env", default="test", help="输入运行环境test 或 live")
parser.add_argument("-m", default=None, help="选择需要运行的用例python.ini配置的名称")
parser.add_argument("-driver", default="chrome",
parser.add_argument("-driver", default="chrome-headless",
help="浏览器驱动类型配置支持如下类型chrome, chrome-headless, firefox, firefox-headless, edge")
args = parser.parse_args()
run(**vars(args))

View File

@ -28,7 +28,7 @@ def case_handle(request):
# 处理用例数据
case = data_handle(obj=case, source=GLOBAL_VARS)
logger.trace(f"当前执行的用例数据:{case}, {type(case)}")
logger.debug(f"当前执行的用例数据:{case}, {type(case)}")
# 添加用例标题作为allure中显示的用例标题
allure_title(case.get("title", ""))

View File

@ -8,56 +8,21 @@
# 标准库导入
# 第三方库导入
import pytest
from requests.utils import dict_from_cookiejar
from loguru import logger
# 本地应用/模块导入
from config.global_vars import GLOBAL_VARS
from case_utils.base_request import BaseRequest
from page_objects.login_page import LoginPage
@pytest.fixture(scope="module")
def login_api():
@pytest.fixture(scope="function")
def login_driver(request):
"""
获取登录的cookie
登录
:return:
"""
driver = request.getfixturevalue("init_driver")
host = GLOBAL_VARS.get("host")
login = GLOBAL_VARS.get('login')
password = GLOBAL_VARS.get('password')
# 兼容一下host后面多一个斜线的情况
if host[-1] == "/":
host = host[:len(host) - 1]
req_data = {
"url": host + "/api/accounts/login.json",
"method": "POST",
"request_type": "json",
"headers": {"Content-Type": "application/json; charset=utf-8;"},
"payload": {"login": login, "password": password, "autologin": 1}
}
# 请求登录接口
try:
res = BaseRequest.send_request(req_data=req_data)
res.raise_for_status()
# 将cookies转成字典
cookies = dict_from_cookiejar(res.cookies)
logger.debug(f"获取用户:{login}登录的cookies成功{type(cookies)} || {cookies}")
yield cookies, res.json()
except Exception as e:
GLOBAL_VARS["login_cookie"] = None
logger.error(f"获取用户:{login}登录的cookies失败{e}")
@pytest.fixture
def write_login_cookies(request, login_api):
driver = request.getfixturevalue("init_driver")
# 遍历 cookies 字典并添加到 WebDriver 中
login_cookies = login_api[0]
for name, value in login_cookies.items():
"""
add_cookie() 方法是 WebDriver 的方法用于向浏览器添加 cookie正确的方法调用应该只有两个参数name value
"""
driver.add_cookie({"name": name, "value": value})
# 刷新页面
driver.refresh()
LoginPage(driver).open_site(host)
LoginPage(driver).login_on_page(login=login, password=password)
yield driver

View File

@ -6,7 +6,6 @@
# @Desc:
# 标准库导入
# 第三方库导入
import time
import pytest
import allure
# 本地应用/模块导入
@ -16,8 +15,7 @@ from page_objects.home_page import HomePage
from page_objects.projects.create_export_project_page import CreateExportProjectPage
from page_objects.projects.repo_common_page import RepoCommonPage
from page_objects.projects.repo_setting_page import RepoSettingPage
from case_utils.data_handle import data_handle
from case_utils.allure_handle import allure_title, allure_step
from case_utils.allure_handle import allure_step
from case_data.create_project_flow_data import *
from loguru import logger
@ -33,7 +31,7 @@ class TestCreateProject:
@allure.story(new_project_success["allure_story"])
@pytest.mark.parametrize("case", new_project_success["cases"],
ids=["{}".format(case["title"]) for case in new_project_success["cases"]])
def test_new_project(self, case, write_login_cookies):
def test_new_project(self, case, login_driver):
"""
名称登录状态下通过右上角导航栏点击新建>新建项目按钮 新建个人公有项目
前提条件
@ -63,8 +61,8 @@ class TestCreateProject:
# 处理URL
host = GLOBAL_VARS.get("host", "")
with allure.step("保持登录态"):
driver = write_login_cookies
with allure.step("输入用户名和密码进行登录"):
driver = login_driver
with allure.step("进入首页"):
HomePage(driver).open_site(host)
@ -123,5 +121,5 @@ class TestCreateProject:
@allure.story(export_project_success["allure_story"])
@pytest.mark.parametrize("case", export_project_success["cases"],
ids=["{}".format(case["title"]) for case in export_project_success["cases"]])
def test_export_project(self, init_driver, case, request):
def test_export_project(self, case, login_driver):
pass

View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
# @Time : 2023/11/22 14:45
# @Author : floraachy
# @File : test_issue
# @Software: PyCharm
# @Desc:
# 标准库导入
import os
# 第三方库导入
import pytest
import allure
# 本地应用/模块导入
from config.global_vars import GLOBAL_VARS
from config.path_config import ATTACH_DIR
from page_objects.projects.repo_issue_page import RepoIssuePage
from page_objects.projects.repo_common_page import RepoCommonPage
from case_utils.allure_handle import allure_step
from case_data.issue_data import *
from loguru import logger
@pytest.mark.issue
@allure.epic(case_common["allure_epic"])
@allure.feature(case_common["allure_feature"])
class TestProjectIssue:
"""
疑修的测试用例
"""
@allure.story(new_issue_success["allure_story"])
@pytest.mark.parametrize("case", new_issue_success["cases"],
ids=["{}".format(case["title"]) for case in new_issue_success["cases"]])
def test_new_issue(self, case, login_driver):
"""
名称登录状态下在测试仓库新建疑修
前提条件
1. 进入测试仓库
2. 写入登录cookies并刷新页面
步骤新建疑修
1. 点击"疑修(Issue)"导航栏
2. 点击"创建疑修"按钮
3. 进入页面${project_url}/issues/new
4. 输入疑修标题内容
5. 上传疑修附件
6. 点击"创建"按钮
7. 疑修创建成功提示: 任务创建成功
断言
1页面进入疑修详情页, 检查网页标题疑修标题内容及附件
"""
# 处理URL
host = GLOBAL_VARS.get("host", "")
with allure.step("输入用户名和密码进行登录"):
driver = login_driver
issue_title = case["issue_title"]
issue_desc = case["issue_desc"]
issue_file = os.path.join(ATTACH_DIR, case["issue_attach"])
with allure.step("访问项目详情页, 点击'疑修(Issue)'导航栏"):
RepoCommonPage(driver).open_site(host=host, project_url=case["project_url"])
RepoCommonPage(driver).click_repo_nav_button(nav="疑修(Issue)")
# ------------------------- 新建疑修-------------------------
with allure.step("点击'创建疑修'按钮"):
RepoIssuePage(driver).click_create_issue_button()
with allure.step("断言--> 进入页面:${project_url}/issues/new"):
assert f"{case['project_url']}/issues/new" in driver.current_url
with allure.step(
"输入疑修标题,内容, 上传疑修附件, 点击'创建'按钮"):
RepoIssuePage(driver).input_issue_title(issue_title=issue_title)
RepoIssuePage(driver).input_issue_desc(issue_desc=issue_desc)
RepoIssuePage(driver).upload_issue_attach(issue_file=issue_file)
RepoIssuePage(driver).submit_issue()
with allure.step("断言--> 疑修创建成功,提示: 任务创建成功!"):
assert "任务创建成功!" == RepoIssuePage(driver).get_issue_success_text()
with allure.step("断言--> 页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件"):
expect = issue_title
actual = RepoIssuePage(driver).get_page_title()
allure_step(step_title=f"断言--> 网页标题包含疑修标题 预期: {expect} 实际:{actual}")
assert expect in actual
expect = issue_title
actual = RepoIssuePage(driver).get_issue_title()
allure_step(step_title=f"断言--> 疑修标题与输入的一致 预期: {expect} 实际:{actual}")
assert expect in actual
expect = issue_desc
actual = RepoIssuePage(driver).get_issue_desc()
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
assert expect in actual
expect = os.path.basename(issue_file)
if isinstance(expect, str):
actual = RepoIssuePage(driver).get_issue_attachments()[0]
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
assert expect in actual
elif isinstance(expect, list):
actual = RepoIssuePage(driver).get_issue_attachments()
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
assert expect in actual