diff --git a/README.md b/README.md index 4b91b4d..e395636 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # 小北原创UI自动化高阶框架selenium+pytest #### 介绍 -免费开源的高级selenium自动化框架,开箱即用,复用性高,可适用任何web项目中 -原创作者:小北 +免费开源的高级selenium自动化框架,开箱即用,复用性高,可适用任何web项目中 +原创作者:小北 微信:xiaobei_upup #### 软件架构 @@ -37,3 +37,13 @@ 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 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 diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/action.py b/common/action.py new file mode 100644 index 0000000..9689908 --- /dev/null +++ b/common/action.py @@ -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 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)) diff --git a/common/image_identify.py b/common/image_identify.py new file mode 100644 index 0000000..6dd7cd3 --- /dev/null +++ b/common/image_identify.py @@ -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 \ No newline at end of file diff --git a/common/logger.py b/common/logger.py new file mode 100644 index 0000000..57e6397 --- /dev/null +++ b/common/logger.py @@ -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') \ No newline at end of file diff --git a/common/login.py b/common/login.py new file mode 100644 index 0000000..cb89b7d --- /dev/null +++ b/common/login.py @@ -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 \ No newline at end of file diff --git a/common/logout.py b/common/logout.py new file mode 100644 index 0000000..77b1d46 --- /dev/null +++ b/common/logout.py @@ -0,0 +1,10 @@ + +""" +------------------------------------------------- + File Name: + Description : + Author : xiaobei + CreateDate: + wechat:xiaobei_upup +------------------------------------------------- +""" \ No newline at end of file diff --git a/common/readconfigini.py b/common/readconfigini.py new file mode 100644 index 0000000..52416de --- /dev/null +++ b/common/readconfigini.py @@ -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) \ No newline at end of file diff --git a/common/screenshots.py b/common/screenshots.py new file mode 100644 index 0000000..4a405dc --- /dev/null +++ b/common/screenshots.py @@ -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")) diff --git a/common/send_mail.py b/common/send_mail.py new file mode 100644 index 0000000..0bbc0d2 --- /dev/null +++ b/common/send_mail.py @@ -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() \ No newline at end of file diff --git a/common/stock_refresh.py b/common/stock_refresh.py new file mode 100644 index 0000000..35e5d8a --- /dev/null +++ b/common/stock_refresh.py @@ -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) diff --git a/common/times.py b/common/times.py new file mode 100644 index 0000000..738a040 --- /dev/null +++ b/common/times.py @@ -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() \ No newline at end of file diff --git a/common/xb_assert.py b/common/xb_assert.py new file mode 100644 index 0000000..3f3d910 --- /dev/null +++ b/common/xb_assert.py @@ -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) \ No newline at end of file diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/conf.py b/config/conf.py new file mode 100644 index 0000000..53b5909 --- /dev/null +++ b/config/conf.py @@ -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) \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..03a2855 --- /dev/null +++ b/conftest.py @@ -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 = '
screenshot
' % 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() diff --git a/data/data.csv b/data/data.csv new file mode 100644 index 0000000..be03bdb --- /dev/null +++ b/data/data.csv @@ -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 diff --git a/data/pytesseract.png b/data/pytesseract.png new file mode 100644 index 0000000..087b378 Binary files /dev/null and b/data/pytesseract.png differ diff --git a/page/__init__.py b/page/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/page/basePage.py b/page/basePage.py new file mode 100644 index 0000000..45e7f29 --- /dev/null +++ b/page/basePage.py @@ -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 + diff --git a/page/zhuifeng_pages/__init__.py b/page/zhuifeng_pages/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/page/zhuifeng_pages/file_upload_pages.py b/page/zhuifeng_pages/file_upload_pages.py new file mode 100644 index 0000000..b893e46 --- /dev/null +++ b/page/zhuifeng_pages/file_upload_pages.py @@ -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() \ No newline at end of file diff --git a/page/zhuifeng_pages/zhuifeng_index.py b/page/zhuifeng_pages/zhuifeng_index.py new file mode 100644 index 0000000..e4dbbdf --- /dev/null +++ b/page/zhuifeng_pages/zhuifeng_index.py @@ -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() + + + diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..41b0df7 --- /dev/null +++ b/pytest.ini @@ -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 \ No newline at end of file diff --git a/reports/195fe866-41c2-4f51-a8dc-6f37398ddd5c-container.json b/reports/195fe866-41c2-4f51-a8dc-6f37398ddd5c-container.json new file mode 100644 index 0000000..fed96b0 --- /dev/null +++ b/reports/195fe866-41c2-4f51-a8dc-6f37398ddd5c-container.json @@ -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} \ No newline at end of file diff --git a/reports/2a3ff856-9324-49c5-9adf-2802c51f85b4-result.json b/reports/2a3ff856-9324-49c5-9adf-2802c51f85b4-result.json new file mode 100644 index 0000000..22df76a --- /dev/null +++ b/reports/2a3ff856-9324-49c5-9adf-2802c51f85b4-result.json @@ -0,0 +1 @@ +{"name": "test_001[wzz-12345]", "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]", "trace": "self = \ndrivers = \n\n @pytest.fixture(scope='function', autouse=True)\n def open_baidu(self, drivers):\n \"\"\"打开百度\"\"\"\n> drivers.get(ConfigManager.ZHUIFENG)\n\ntestcases\\zhuifeng_tc\\test_ddt_zhuifeng.py:33: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py:449: in get\n self.execute(Command.GET, {\"url\": url})\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py:440: in execute\n self.error_handler.check_response(response)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = \nresponse = {'status': 404, 'value': '{\"value\":{\"error\":\"no such window\",\"message\":\"no such window: target window already closed\\\\...\\n\\\\tRtlGetAppContainerNamedObjectPath [0x77507B1E+286]\\\\n\\\\tRtlGetAppContainerNamedObjectPath [0x77507AEE+238]\\\\n\"}}'}\n\n def check_response(self, response: Dict[str, Any]) -> None:\n \"\"\"Checks that a JSON response from the WebDriver does not have an\n error.\n \n :Args:\n - response - The JSON response from the WebDriver server as a dictionary\n object.\n \n :Raises: If the response contains an error message.\n \"\"\"\n status = response.get(\"status\", None)\n if not status or status == ErrorCode.SUCCESS:\n return\n value = None\n message = response.get(\"message\", \"\")\n screen: str = response.get(\"screen\", \"\")\n stacktrace = None\n if isinstance(status, int):\n value_json = response.get(\"value\", None)\n if value_json and isinstance(value_json, str):\n import json\n \n try:\n value = json.loads(value_json)\n if len(value) == 1:\n value = value[\"value\"]\n status = value.get(\"error\", None)\n if not status:\n status = value.get(\"status\", ErrorCode.UNKNOWN_ERROR)\n message = value.get(\"value\") or value.get(\"message\")\n if not isinstance(message, str):\n value = message\n message = message.get(\"message\")\n else:\n message = value.get(\"message\", None)\n except ValueError:\n pass\n \n exception_class: Type[WebDriverException]\n if status in ErrorCode.NO_SUCH_ELEMENT:\n exception_class = NoSuchElementException\n elif status in ErrorCode.NO_SUCH_FRAME:\n exception_class = NoSuchFrameException\n elif status in ErrorCode.NO_SUCH_SHADOW_ROOT:\n exception_class = NoSuchShadowRootException\n elif status in ErrorCode.NO_SUCH_WINDOW:\n exception_class = NoSuchWindowException\n elif status in ErrorCode.STALE_ELEMENT_REFERENCE:\n exception_class = StaleElementReferenceException\n elif status in ErrorCode.ELEMENT_NOT_VISIBLE:\n exception_class = ElementNotVisibleException\n elif status in ErrorCode.INVALID_ELEMENT_STATE:\n exception_class = InvalidElementStateException\n elif (\n status in ErrorCode.INVALID_SELECTOR\n or status in ErrorCode.INVALID_XPATH_SELECTOR\n or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER\n ):\n exception_class = InvalidSelectorException\n elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:\n exception_class = ElementNotSelectableException\n elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:\n exception_class = ElementNotInteractableException\n elif status in ErrorCode.INVALID_COOKIE_DOMAIN:\n exception_class = InvalidCookieDomainException\n elif status in ErrorCode.UNABLE_TO_SET_COOKIE:\n exception_class = UnableToSetCookieException\n elif status in ErrorCode.TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.SCRIPT_TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.UNKNOWN_ERROR:\n exception_class = WebDriverException\n elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:\n exception_class = UnexpectedAlertPresentException\n elif status in ErrorCode.NO_ALERT_OPEN:\n exception_class = NoAlertPresentException\n elif status in ErrorCode.IME_NOT_AVAILABLE:\n exception_class = ImeNotAvailableException\n elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:\n exception_class = ImeActivationFailedException\n elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:\n exception_class = MoveTargetOutOfBoundsException\n elif status in ErrorCode.JAVASCRIPT_ERROR:\n exception_class = JavascriptException\n elif status in ErrorCode.SESSION_NOT_CREATED:\n exception_class = SessionNotCreatedException\n elif status in ErrorCode.INVALID_ARGUMENT:\n exception_class = InvalidArgumentException\n elif status in ErrorCode.NO_SUCH_COOKIE:\n exception_class = NoSuchCookieException\n elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:\n exception_class = ScreenshotException\n elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:\n exception_class = ElementClickInterceptedException\n elif status in ErrorCode.INSECURE_CERTIFICATE:\n exception_class = InsecureCertificateException\n elif status in ErrorCode.INVALID_COORDINATES:\n exception_class = InvalidCoordinatesException\n elif status in ErrorCode.INVALID_SESSION_ID:\n exception_class = InvalidSessionIdException\n elif status in ErrorCode.UNKNOWN_METHOD:\n exception_class = UnknownMethodException\n else:\n exception_class = WebDriverException\n if not value:\n value = response[\"value\"]\n if isinstance(value, str):\n raise exception_class(value)\n if message == \"\" and \"message\" in value:\n message = value[\"message\"]\n \n screen = None # type: ignore[assignment]\n if \"screen\" in value:\n screen = value[\"screen\"]\n \n stacktrace = None\n st_value = value.get(\"stackTrace\") or value.get(\"stacktrace\")\n if st_value:\n if isinstance(st_value, str):\n stacktrace = st_value.split(\"\\n\")\n else:\n stacktrace = []\n try:\n for frame in st_value:\n line = frame.get(\"lineNumber\", \"\")\n file = frame.get(\"fileName\", \"\")\n if line:\n file = f\"{file}:{line}\"\n meth = frame.get(\"methodName\", \"\")\n if \"className\" in frame:\n meth = f\"{frame['className']}.{meth}\"\n msg = \" at %s (%s)\"\n msg = msg % (meth, file)\n stacktrace.append(msg)\n except TypeError:\n pass\n if exception_class == UnexpectedAlertPresentException:\n alert_text = None\n if \"data\" in value:\n alert_text = value[\"data\"].get(\"text\")\n elif \"alert\" in value:\n alert_text = value[\"alert\"].get(\"text\")\n raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here\n> raise exception_class(message, screen, stacktrace)\nE selenium.common.exceptions.NoSuchWindowException: Message: no such window: target window already closed\nE from unknown error: web view not found\nE (Session info: chrome=114.0.5735.199)\nE Stacktrace:\nE Backtrace:\nE \tGetHandleVerifier [0x0038A813+48355]\nE \t(No symbol) [0x0031C4B1]\nE \t(No symbol) [0x00225358]\nE \t(No symbol) [0x0020D293]\nE \t(No symbol) [0x0026E37B]\nE \t(No symbol) [0x0027C473]\nE \t(No symbol) [0x0026A536]\nE \t(No symbol) [0x002482DC]\nE \t(No symbol) [0x002493DD]\nE \tGetHandleVerifier [0x005EAABD+2539405]\nE \tGetHandleVerifier [0x0062A78F+2800735]\nE \tGetHandleVerifier [0x0062456C+2775612]\nE \tGetHandleVerifier [0x004151E0+616112]\nE \t(No symbol) [0x00325F8C]\nE \t(No symbol) [0x00322328]\nE \t(No symbol) [0x0032240B]\nE \t(No symbol) [0x00314FF7]\nE \tBaseThreadInitThunk [0x764B00C9+25]\nE \tRtlGetAppContainerNamedObjectPath [0x77507B1E+286]\nE \tRtlGetAppContainerNamedObjectPath [0x77507AEE+238]\n\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\errorhandler.py:245: NoSuchWindowException"}, "parameters": [{"name": "username", "value": "'wzz'"}, {"name": "password", "value": "'12345'"}], "start": 1691998115956, "stop": 1691998115956, "uuid": "4e339847-f374-4691-9f96-6b87e2d51832", "historyId": "04817041a266e038b92df44b17818161", "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"}]} \ No newline at end of file diff --git a/reports/310d5185-ed63-4cab-9e19-9730dda0c60e-container.json b/reports/310d5185-ed63-4cab-9e19-9730dda0c60e-container.json new file mode 100644 index 0000000..35f6c86 --- /dev/null +++ b/reports/310d5185-ed63-4cab-9e19-9730dda0c60e-container.json @@ -0,0 +1 @@ +{"uuid": "5fc06f2f-c6ae-4e11-ae8f-f25706efe8d2", "befores": [{"name": "username", "status": "passed", "start": 1691998105893, "stop": 1691998105893}], "start": 1691998105893, "stop": 1691998115417} \ No newline at end of file diff --git a/reports/3d57b3ab-3556-45f6-976a-8cb84cd15af6-container.json b/reports/3d57b3ab-3556-45f6-976a-8cb84cd15af6-container.json new file mode 100644 index 0000000..7ed796e --- /dev/null +++ b/reports/3d57b3ab-3556-45f6-976a-8cb84cd15af6-container.json @@ -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} \ No newline at end of file diff --git a/reports/747f09b3-d3d8-488d-94b3-c8e786c2246a-container.json b/reports/747f09b3-d3d8-488d-94b3-c8e786c2246a-container.json new file mode 100644 index 0000000..1f9dac2 --- /dev/null +++ b/reports/747f09b3-d3d8-488d-94b3-c8e786c2246a-container.json @@ -0,0 +1 @@ +{"uuid": "506fc813-3192-40a1-88e1-52788dbbc862", "befores": [{"name": "username", "status": "passed", "start": 1691998115751, "stop": 1691998115752}], "start": 1691998115751, "stop": 1691998115941} \ No newline at end of file diff --git a/reports/9aadc58b-21c1-4bfa-b912-874dd14da0f5-result.json b/reports/9aadc58b-21c1-4bfa-b912-874dd14da0f5-result.json new file mode 100644 index 0000000..2dfe5ff --- /dev/null +++ b/reports/9aadc58b-21c1-4bfa-b912-874dd14da0f5-result.json @@ -0,0 +1 @@ +{"name": "test_001[user2-pass2]", "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]", "trace": "self = \ndrivers = \nusername = 'user2', password = 'pass2'\n\n @pytest.mark.smoke\n @pytest.mark.parametrize('username, password', [\n ('user1', 'pass1'),\n ('user2', 'pass2'),\n ('wzz', '12345')\n ])\n def test_001(self, drivers, username, password):\n zhufeng = zhuifeng_index_page(drivers)\n> zhufeng.input_account = username\n\ntestcases\\zhuifeng_tc\\test_ddt_zhuifeng.py:45: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\npage\\basePage.py:80: in __set__\n elem = self.__get__(instance, instance.__class__)\npage\\basePage.py:74: in __get__\n return WebDriverWait(context, 5, 1).until(lambda x: x.find_element(*self.locator))\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\support\\wait.py:86: in until\n value = method(self._driver)\npage\\basePage.py:74: in \n return WebDriverWait(context, 5, 1).until(lambda x: x.find_element(*self.locator))\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py:831: in find_element\n return self.execute(Command.FIND_ELEMENT, {\"using\": by, \"value\": value})[\"value\"]\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\webdriver.py:440: in execute\n self.error_handler.check_response(response)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\nself = \nresponse = {'status': 404, 'value': '{\"value\":{\"error\":\"no such window\",\"message\":\"no such window: target window already closed\\\\...\\n\\\\tRtlGetAppContainerNamedObjectPath [0x77507B1E+286]\\\\n\\\\tRtlGetAppContainerNamedObjectPath [0x77507AEE+238]\\\\n\"}}'}\n\n def check_response(self, response: Dict[str, Any]) -> None:\n \"\"\"Checks that a JSON response from the WebDriver does not have an\n error.\n \n :Args:\n - response - The JSON response from the WebDriver server as a dictionary\n object.\n \n :Raises: If the response contains an error message.\n \"\"\"\n status = response.get(\"status\", None)\n if not status or status == ErrorCode.SUCCESS:\n return\n value = None\n message = response.get(\"message\", \"\")\n screen: str = response.get(\"screen\", \"\")\n stacktrace = None\n if isinstance(status, int):\n value_json = response.get(\"value\", None)\n if value_json and isinstance(value_json, str):\n import json\n \n try:\n value = json.loads(value_json)\n if len(value) == 1:\n value = value[\"value\"]\n status = value.get(\"error\", None)\n if not status:\n status = value.get(\"status\", ErrorCode.UNKNOWN_ERROR)\n message = value.get(\"value\") or value.get(\"message\")\n if not isinstance(message, str):\n value = message\n message = message.get(\"message\")\n else:\n message = value.get(\"message\", None)\n except ValueError:\n pass\n \n exception_class: Type[WebDriverException]\n if status in ErrorCode.NO_SUCH_ELEMENT:\n exception_class = NoSuchElementException\n elif status in ErrorCode.NO_SUCH_FRAME:\n exception_class = NoSuchFrameException\n elif status in ErrorCode.NO_SUCH_SHADOW_ROOT:\n exception_class = NoSuchShadowRootException\n elif status in ErrorCode.NO_SUCH_WINDOW:\n exception_class = NoSuchWindowException\n elif status in ErrorCode.STALE_ELEMENT_REFERENCE:\n exception_class = StaleElementReferenceException\n elif status in ErrorCode.ELEMENT_NOT_VISIBLE:\n exception_class = ElementNotVisibleException\n elif status in ErrorCode.INVALID_ELEMENT_STATE:\n exception_class = InvalidElementStateException\n elif (\n status in ErrorCode.INVALID_SELECTOR\n or status in ErrorCode.INVALID_XPATH_SELECTOR\n or status in ErrorCode.INVALID_XPATH_SELECTOR_RETURN_TYPER\n ):\n exception_class = InvalidSelectorException\n elif status in ErrorCode.ELEMENT_IS_NOT_SELECTABLE:\n exception_class = ElementNotSelectableException\n elif status in ErrorCode.ELEMENT_NOT_INTERACTABLE:\n exception_class = ElementNotInteractableException\n elif status in ErrorCode.INVALID_COOKIE_DOMAIN:\n exception_class = InvalidCookieDomainException\n elif status in ErrorCode.UNABLE_TO_SET_COOKIE:\n exception_class = UnableToSetCookieException\n elif status in ErrorCode.TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.SCRIPT_TIMEOUT:\n exception_class = TimeoutException\n elif status in ErrorCode.UNKNOWN_ERROR:\n exception_class = WebDriverException\n elif status in ErrorCode.UNEXPECTED_ALERT_OPEN:\n exception_class = UnexpectedAlertPresentException\n elif status in ErrorCode.NO_ALERT_OPEN:\n exception_class = NoAlertPresentException\n elif status in ErrorCode.IME_NOT_AVAILABLE:\n exception_class = ImeNotAvailableException\n elif status in ErrorCode.IME_ENGINE_ACTIVATION_FAILED:\n exception_class = ImeActivationFailedException\n elif status in ErrorCode.MOVE_TARGET_OUT_OF_BOUNDS:\n exception_class = MoveTargetOutOfBoundsException\n elif status in ErrorCode.JAVASCRIPT_ERROR:\n exception_class = JavascriptException\n elif status in ErrorCode.SESSION_NOT_CREATED:\n exception_class = SessionNotCreatedException\n elif status in ErrorCode.INVALID_ARGUMENT:\n exception_class = InvalidArgumentException\n elif status in ErrorCode.NO_SUCH_COOKIE:\n exception_class = NoSuchCookieException\n elif status in ErrorCode.UNABLE_TO_CAPTURE_SCREEN:\n exception_class = ScreenshotException\n elif status in ErrorCode.ELEMENT_CLICK_INTERCEPTED:\n exception_class = ElementClickInterceptedException\n elif status in ErrorCode.INSECURE_CERTIFICATE:\n exception_class = InsecureCertificateException\n elif status in ErrorCode.INVALID_COORDINATES:\n exception_class = InvalidCoordinatesException\n elif status in ErrorCode.INVALID_SESSION_ID:\n exception_class = InvalidSessionIdException\n elif status in ErrorCode.UNKNOWN_METHOD:\n exception_class = UnknownMethodException\n else:\n exception_class = WebDriverException\n if not value:\n value = response[\"value\"]\n if isinstance(value, str):\n raise exception_class(value)\n if message == \"\" and \"message\" in value:\n message = value[\"message\"]\n \n screen = None # type: ignore[assignment]\n if \"screen\" in value:\n screen = value[\"screen\"]\n \n stacktrace = None\n st_value = value.get(\"stackTrace\") or value.get(\"stacktrace\")\n if st_value:\n if isinstance(st_value, str):\n stacktrace = st_value.split(\"\\n\")\n else:\n stacktrace = []\n try:\n for frame in st_value:\n line = frame.get(\"lineNumber\", \"\")\n file = frame.get(\"fileName\", \"\")\n if line:\n file = f\"{file}:{line}\"\n meth = frame.get(\"methodName\", \"\")\n if \"className\" in frame:\n meth = f\"{frame['className']}.{meth}\"\n msg = \" at %s (%s)\"\n msg = msg % (meth, file)\n stacktrace.append(msg)\n except TypeError:\n pass\n if exception_class == UnexpectedAlertPresentException:\n alert_text = None\n if \"data\" in value:\n alert_text = value[\"data\"].get(\"text\")\n elif \"alert\" in value:\n alert_text = value[\"alert\"].get(\"text\")\n raise exception_class(message, screen, stacktrace, alert_text) # type: ignore[call-arg] # mypy is not smart enough here\n> raise exception_class(message, screen, stacktrace)\nE selenium.common.exceptions.NoSuchWindowException: Message: no such window: target window already closed\nE from unknown error: web view not found\nE (Session info: chrome=114.0.5735.199)\nE Stacktrace:\nE Backtrace:\nE \tGetHandleVerifier [0x0038A813+48355]\nE \t(No symbol) [0x0031C4B1]\nE \t(No symbol) [0x00225358]\nE \t(No symbol) [0x0020D293]\nE \t(No symbol) [0x0026E37B]\nE \t(No symbol) [0x0027C473]\nE \t(No symbol) [0x0026A536]\nE \t(No symbol) [0x002482DC]\nE \t(No symbol) [0x002493DD]\nE \tGetHandleVerifier [0x005EAABD+2539405]\nE \tGetHandleVerifier [0x0062A78F+2800735]\nE \tGetHandleVerifier [0x0062456C+2775612]\nE \tGetHandleVerifier [0x004151E0+616112]\nE \t(No symbol) [0x00325F8C]\nE \t(No symbol) [0x00322328]\nE \t(No symbol) [0x0032240B]\nE \t(No symbol) [0x00314FF7]\nE \tBaseThreadInitThunk [0x764B00C9+25]\nE \tRtlGetAppContainerNamedObjectPath [0x77507B1E+286]\nE \tRtlGetAppContainerNamedObjectPath [0x77507AEE+238]\n\n..\\..\\env_dependence\\Python\\Lib\\site-packages\\selenium\\webdriver\\remote\\errorhandler.py:245: NoSuchWindowException"}, "parameters": [{"name": "username", "value": "'user2'"}, {"name": "password", "value": "'pass2'"}], "start": 1691998115755, "stop": 1691998115758, "uuid": "ee15855b-c6d9-4be8-b5ff-f67ef1bdad75", "historyId": "8f129242676ad0294cab486a80336983", "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"}]} \ No newline at end of file diff --git a/reports/b202c295-6dcf-4160-a8f6-43690bbf3f39-result.json b/reports/b202c295-6dcf-4160-a8f6-43690bbf3f39-result.json new file mode 100644 index 0000000..71b9173 --- /dev/null +++ b/reports/b202c295-6dcf-4160-a8f6-43690bbf3f39-result.json @@ -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"}]} \ No newline at end of file diff --git a/reports/b7f6f78b-1489-44d2-acb7-719309a1bcd3-container.json b/reports/b7f6f78b-1489-44d2-acb7-719309a1bcd3-container.json new file mode 100644 index 0000000..ed153e9 --- /dev/null +++ b/reports/b7f6f78b-1489-44d2-acb7-719309a1bcd3-container.json @@ -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} \ No newline at end of file diff --git a/reports/de4ab148-f0c2-4ba8-9bec-2fb2c06a4ce4-container.json b/reports/de4ab148-f0c2-4ba8-9bec-2fb2c06a4ce4-container.json new file mode 100644 index 0000000..4b75439 --- /dev/null +++ b/reports/de4ab148-f0c2-4ba8-9bec-2fb2c06a4ce4-container.json @@ -0,0 +1 @@ +{"uuid": "7597ef3d-c261-44de-85ab-4859306a7342", "befores": [{"name": "password", "status": "passed", "start": 1691998105893, "stop": 1691998105893}], "start": 1691998105893, "stop": 1691998115416} \ No newline at end of file diff --git a/reports/e03def0e-f7f1-4f89-9900-998b3b695215-container.json b/reports/e03def0e-f7f1-4f89-9900-998b3b695215-container.json new file mode 100644 index 0000000..e25efb9 --- /dev/null +++ b/reports/e03def0e-f7f1-4f89-9900-998b3b695215-container.json @@ -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} \ No newline at end of file diff --git a/reports/f7687dce-6871-4486-889c-78a88b042eb9-container.json b/reports/f7687dce-6871-4486-889c-78a88b042eb9-container.json new file mode 100644 index 0000000..6517f77 --- /dev/null +++ b/reports/f7687dce-6871-4486-889c-78a88b042eb9-container.json @@ -0,0 +1 @@ +{"uuid": "f32cd291-f80c-4b2e-a1d4-3fa05d9d7fea", "befores": [{"name": "password", "status": "passed", "start": 1691998115752, "stop": 1691998115752}], "start": 1691998115752, "stop": 1691998115939} \ No newline at end of file diff --git a/screenshots/小北微信.jpg b/screenshots/小北微信.jpg new file mode 100644 index 0000000..0343c65 Binary files /dev/null and b/screenshots/小北微信.jpg differ diff --git a/testcases/__init__.py b/testcases/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/testcases/zhuifeng_tc/__init__.py b/testcases/zhuifeng_tc/__init__.py new file mode 100644 index 0000000..6906135 --- /dev/null +++ b/testcases/zhuifeng_tc/__init__.py @@ -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 \ No newline at end of file diff --git a/testcases/zhuifeng_tc/crop_pic.png b/testcases/zhuifeng_tc/crop_pic.png new file mode 100644 index 0000000..d2924e7 Binary files /dev/null and b/testcases/zhuifeng_tc/crop_pic.png differ diff --git a/testcases/zhuifeng_tc/reports/2824e895-0e67-4d53-b478-99add8cd611e-container.json b/testcases/zhuifeng_tc/reports/2824e895-0e67-4d53-b478-99add8cd611e-container.json new file mode 100644 index 0000000..fe51472 --- /dev/null +++ b/testcases/zhuifeng_tc/reports/2824e895-0e67-4d53-b478-99add8cd611e-container.json @@ -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} \ No newline at end of file diff --git a/testcases/zhuifeng_tc/reports/30be89b9-3318-4d43-bbbe-577ee04127cc-container.json b/testcases/zhuifeng_tc/reports/30be89b9-3318-4d43-bbbe-577ee04127cc-container.json new file mode 100644 index 0000000..a2116cc --- /dev/null +++ b/testcases/zhuifeng_tc/reports/30be89b9-3318-4d43-bbbe-577ee04127cc-container.json @@ -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} \ No newline at end of file diff --git a/testcases/zhuifeng_tc/reports/4a698d4b-2961-4f4f-b064-744c5153a7d4-result.json b/testcases/zhuifeng_tc/reports/4a698d4b-2961-4f4f-b064-744c5153a7d4-result.json new file mode 100644 index 0000000..c59c482 --- /dev/null +++ b/testcases/zhuifeng_tc/reports/4a698d4b-2961-4f4f-b064-744c5153a7d4-result.json @@ -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"}]} \ No newline at end of file diff --git a/testcases/zhuifeng_tc/reports/711e2675-d749-4e2d-94cf-598f15d8a788-container.json b/testcases/zhuifeng_tc/reports/711e2675-d749-4e2d-94cf-598f15d8a788-container.json new file mode 100644 index 0000000..3f676d9 --- /dev/null +++ b/testcases/zhuifeng_tc/reports/711e2675-d749-4e2d-94cf-598f15d8a788-container.json @@ -0,0 +1 @@ +{"uuid": "7f2b1f3e-3d70-4378-8776-469aef9249b0", "befores": [{"name": "password", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424124} \ No newline at end of file diff --git a/testcases/zhuifeng_tc/reports/d5de98d0-5cd2-4a3a-a694-1d19191d99d2-container.json b/testcases/zhuifeng_tc/reports/d5de98d0-5cd2-4a3a-a694-1d19191d99d2-container.json new file mode 100644 index 0000000..3f5b0ae --- /dev/null +++ b/testcases/zhuifeng_tc/reports/d5de98d0-5cd2-4a3a-a694-1d19191d99d2-container.json @@ -0,0 +1 @@ +{"uuid": "1bcd466c-4cff-414e-b378-8b136d4b2a10", "befores": [{"name": "username", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424126} \ No newline at end of file diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng.py new file mode 100644 index 0000000..fde09f9 --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng.py @@ -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']) diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py new file mode 100644 index 0000000..43d8597 --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.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']) + diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file2.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file2.py new file mode 100644 index 0000000..67ba63e --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file2.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' + diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file3.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file3.py new file mode 100644 index 0000000..14c8dc6 --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file3.py @@ -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() diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file4.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file4.py new file mode 100644 index 0000000..a55b0f9 --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file4.py @@ -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() diff --git a/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file5.py b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file5.py new file mode 100644 index 0000000..c9d6d03 --- /dev/null +++ b/testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file5.py @@ -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() diff --git a/testcases/zhuifeng_tc/test_file_upload.py b/testcases/zhuifeng_tc/test_file_upload.py new file mode 100644 index 0000000..9ec8c39 --- /dev/null +++ b/testcases/zhuifeng_tc/test_file_upload.py @@ -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']) diff --git a/testcases/zhuifeng_tc/test_zhuifeng_system.py b/testcases/zhuifeng_tc/test_zhuifeng_system.py new file mode 100644 index 0000000..2b21187 --- /dev/null +++ b/testcases/zhuifeng_tc/test_zhuifeng_system.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() + diff --git a/testcases/zhuifeng_tc/whole_pic.png b/testcases/zhuifeng_tc/whole_pic.png new file mode 100644 index 0000000..9cf149c Binary files /dev/null and b/testcases/zhuifeng_tc/whole_pic.png differ