windows下python版web自动化测试框架(完整搭建流程引导)

    科技2024-11-13  12

    https://blog.csdn.net/weixin_45912307/article/details/108955085

    windows下python版web自动化测试框架 (完整搭建流程引导)

    一、项目环境准备工作二、 创建项目(以pycharm为例)三、框架的封装1. 创建框架目录2. 公共层3. 输出层4. 页面元素定位层5. 页面对象层(操作方法)6. 测试用例层7. 测试数据层8. readme.md 帮助文件9. requirements.txt 项目依赖工具包10.run.py 项目运行文件 四、与Jenkins集成

    一、项目环境准备工作

    1.配置虚拟环境, 请参考之前一篇文章:https://blog.csdn.net/weixin_45912307/article/details/108347547

    2. 创建项目虚拟环境 mkvirtualenv -p python3 虚拟环境名称

    二、 创建项目(以pycharm为例)

    1. 点击 new project 2. 先找到刚刚创建好的虚拟环境目录

    3. 创建工程目录

    4. 选择好虚拟环境,选择好工程目录,点击创建 5. 创建好的工程目录架构

    三、框架的封装

    1. 创建框架目录

    最终框架结构如图:

    2. 公共层

    2.1 base_page.py 页面公共函数

    # —— coding :utf-8 —— # @time: 2020/10/7 20:58 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: base_page.py import logging import datetime from selenium.webdriver import ActionChains from selenium.webdriver.common.keys import Keys from Common.file_path import screenshots_path from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time import win32gui import win32con # pip install pywin32 class BasePage: def __init__(self, driver): self.driver = driver # 1. 等待元素可见 def wait_eleVisible(self, locator, timeout=20, poll_frequency=0.5, doc=""): """ :param locator: 元素定位,元组形式。 (元素类型,元素定位方式) :param timeout: :param poll_frequency: :param doc: 模块名称_页面名称_操作名称 :return: """ logging.info('等待元素可见:{}可见'.format(locator)) try: # 开始等待时间 start_time = datetime.datetime.now() WebDriverWait(self.driver, timeout, poll_frequency).until(EC.visibility_of_element_located(locator)) # 结束等待时间 end_time = datetime.datetime.now() # 等待时长,转换为s wait_times = (end_time - start_time).seconds logging.info( "{0}:元素:{1}已可见,等待起始时间:{2},等待结束时间:{3},等待时间:{4}".format(doc, locator, start_time, end_time, wait_times)) except: # 铺获异常到日志中 # 截图--保存到指定目录 logging.exception('等待元素可见失败!') self.save_screenshot(doc) raise # 2. 判断元素是否存在 def ele_isExist(self, locator, timeout=10, doc=""): logging.info("{}中是否存在元素:{}".format(doc, locator)) try: WebDriverWait(self.driver, timeout).until(EC.visibility_of_element_located(locator)) logging.info("{0}秒内页面{1}存在中存在元素:{2}".format(timeout, doc, locator)) return True except: logging.exception("{0}秒内页面{1}存在中不存在元素:{2}".format(timeout, doc, locator)) return False # 3. 查找元素 def find_element(self, locator, doc=""): logging.info('{0}查找元素:{1}'.format(doc, locator)) try: return self.driver.find_element(*locator) except: logging.exception('查找元素失败') self.save_screenshot(doc) raise # 3. 判断元素是否存在 # 4. 点击操作 def click_element(self, locator, doc): ele = self.find_element(locator, doc) logging.info('{0}点击元素:{1}'.format(doc, locator)) try: ele.click() logging.info('{0}点击元素:{1}成功'.format(doc, locator)) except: logging.exception('元素点击操作失败!') self.save_screenshot(doc) raise # 5. 输入操作 def input_text(self, locator, content, doc=""): ele = self.find_element(locator, doc) logging.info('{0}元素:{1}输入文本'.format(doc, locator)) try: logging.info('{0}元素:{1},输入内容为:{2}'.format(doc, locator, content)) ele.send_keys(content) except: logging.exception('{0}元素:{1}输入失败'.format(doc, locator)) self.save_screenshot(doc) raise # 6. 获取元素文本 def get_element_text(self, locator, text, doc=""): ele = self.find_element(locator, doc) logging.info('{0}获取元素:{1}的文本内容'.format(doc, locator)) try: text = ele.text logging.info('{0}获取元素:{1}的文本内容为:{2}'.format(doc, locator, text)) return text except: logging.exception('获取元素:{}文本内容失败'.format(locator)) self.save_screenshot(doc) raise # 7. 获取元素属性 def get_element_attribute(self, locator, attr, doc=""): ele = self.find_element(locator, doc) logging.info('{0}获取元素:{1}的属性:{2}'.format(doc, locator, attr)) try: ele_attr = ele.get_attribute(attr) logging.info('{0}元素:{1}的属性:{2}值为:{3}'.format(doc, locator, attr, ele_attr)) return ele_attr except: logging.exception('{}获取元素:{}的属性失败'.format(doc, locator)) self.save_screenshot(doc) raise # 8. alert处理 def switch_to_alert(self, timeout=30, poll_frequency=0.5, action='accept', doc=""): logging.info('{0}_切换alert弹框'.format(doc)) try: WebDriverWait(self.driver, timeout, poll_frequency).until(EC.alert_is_present()) alert = self.driver.switch_to.alert value = alert.text logging.info('{0}当前弹框内容为:{1}'.format(doc, value)) if action == 'accept': alert.accept() elif action == 'dismiss': alert.dismiss() return value except: logging.exception('{}弹框操作失败!'.format(doc)) self.save_screenshot(doc) raise # 9. 保存截图 def save_screenshot(self, doc): # 图片名称:模块名_页面名称_操作名称_年-月-日_时分秒.png # filePath = "截图路径" + "{0}".format(time.strftime("%Y%m%d%H%M%S")) filePath = screenshots_path + "{0}_{1}.png".format(doc, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) try: self.driver.save_screenshot(filePath) logging.info("截取网页成功,文件路径为:{}".format(filePath)) except: logging.exception('保存网页失败!') raise # 10. 滚动条处理 def scrollbal_handle(self,url,mode='foot',doc=""): global js logging.info('{}进行滚动条操作'.format(doc)) try: self.driver.get(url) if mode=='top': # 滚动到顶部 js = "window.scrollTo(0,0)" self.driver.execute_script(js) else: # 滚动到底部 js = "window.scrollTo(0,document.body.scrollHeight)" self.driver.execute_script(js) logging.info('{}滚动成功'.format(doc)) except: logging.exception('{}滚动操作失败'.format(doc)) self.save_screenshot(doc) raise # 11. 上传操作 def upload_file(self, UpfilePath,doc=""): logging.info('{}进行文件上传'.format(doc)) try: dialog = win32gui.FindWindow('#32770', '打开') # 一级 # 二级窗口 ComBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComBoxEx32', None) # 三级窗口 ComboBox = win32gui.FindWindowEx(ComBoxEx32, 0, 'ComboBox', None) # 四级窗口 edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None) button = win32gui.FindWindowEx(dialog, 0, 'Button', "打开(&0)") # 操作 # 输入文件地址 win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, UpfilePath) # 发送文件路径 # 打开文件按钮 win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) # 点击打开按钮 logging.info('{}文件上传成功'.format(doc)) except: logging.exception('{}文件上传操作失败'.format(doc)) self.save_screenshot(doc) raise # 12. iframe切换 def switch_to_frame(self,locator,doc=""): ele = self.find_element(locator) logging.info('{}表单切换'.format(doc)) try: self.driver.switch_to.frame(ele) logging.info('{}切换表单成功'.format(doc)) except: logging.exception('{}切换表单失败!'.format(doc)) self.save_screenshot(doc) raise # 13. 窗口切换 def switch_to_window(self, window_reference, timeout=30, poll_frequency=0.5, window_handles=None, doc=""): logging.info("{0}_切换窗口".format(doc)) try: if window_reference == "new": if window_handles: WebDriverWait(timeout, poll_frequency).until(EC.new_window_is_opened(window_handles)) current_window_handles = self.driver.window_handles self.driver.switch_to.window(current_window_handles[-1]) else: logging.exception("打开新窗口时,请传入window_handles参数") raise ("打开新窗口时,请传入window_handles参数") elif window_reference == "default": self.driver.switch_to.default_content() else: self.driver.switch_to.window(window_reference) logging.info("{0}_切换窗口成功".format(doc)) except: logging.exception("{0}_切换窗口失败".format(doc)) self.save_screenshot(doc) raise # 14. 执行js def execute_script(self, js_str, element_info=None,doc=""): logging.info('{}执行js'.format(doc)) try: if element_info: self.driver.execute_script(js_str) else: self.driver.execute_script(js_str, None) logging.info('{}执行js成功'.format(doc)) except: logging.exception('{}执行js操作失败'.format(doc)) self.save_screenshot(doc) raise # 15. 鼠标事件 # 元素鼠标操作:右击-测试OK def context_click(self, locator): mouse = ActionChains(self.driver) ele = self.find_element(self,locator) logging.info('{}元素进行右击操作'.format(locator)) mouse.context_click(ele).perform() # 元素鼠标操作:移动到该元素上--测试OK def move_to_element_by_mouse(self, locator): ele = self.find_element(locator) mouse = ActionChains(self.driver) logging.info('将鼠标移动到{}元素上'.format(locator)) mouse.move_to_element(ele).perform() # 长按元素 def long_press_element(self, locator, seconds): ele = self.find_element(locator) logging.info('将鼠标长按到{}元素上后松开'.format(locator)) mouse = ActionChains(self.driver) mouse.click_and_hold(ele).pause(seconds).release(ele) def scrollIntoView(self, locator): ele = self.find_element(locator) logging.info('将滚动条滚动至{}元素可见'.format(locator)) self.driver.execute_script('arguments[0].scrollIntoView();', ele) time.sleep(1) # 16. 键盘事件 # 删除内容-测试OK def back_space(self, locator): ele = self.find_element(locator) logging.info('{0}元素操作back_space'.format(locator)) ele.send_keys(Keys.BACK_SPACE) # 清空内容--测试OK def clear_input(self,locator): ele = self.find_element(locator) logging.info('{}元素输入框操作清空'.format(locator)) ele.clear() # 按回车--测试OK def enter(self, locator): ele = self.find_element(locator) logging.info('{}元素进行回车键操作'.format(logging)) ele.send_keys(Keys.ENTER) # 全选 Ctrl+a--测试OK def ctrl_a(self,locator): ele = self.find_element(locator) logging.info('{}元素输入框内容进行全选操作'.format(locator)) ele.send_keys(Keys.CONTROL, 'a') # 粘贴 Ctrl +x--测试OK def ctrl_x(self,locator): ele = self.find_element(locator) logging.info('{}元素输入框内容进行剪切操作'.format(locator)) ele.send_keys(Keys.CONTROL, 'x') # 粘贴 Ctrl +v--测试OK def ctrl_v(self, locator): ele = self.find_element(locator) logging.info('{}元素输入框内容进行粘贴操作'.format(locator)) ele.send_keys(Keys.CONTROL, 'v') # 17. 等待操作 def implicitly_wait(self, seconds=30): self.driver.implicitly_wait(seconds) def wait(self, seconds=20): time.sleep(seconds) # 18.浏览器操作 def open_url(self, url): self.driver.get(url) logging.info('打开URL地址%s;' % url) def set_browser_max(self): self.driver.maximize_window() logging.info("设置浏览器的最大化") def close_tab(self): self.driver.close() logging.info('关闭当前的tab页签') def set_browser_min(self): self.driver.minimize_window() logging.info("设置浏览器的最小化") def browser_refresh(self): self.driver.refresh() logging.info("浏览器的刷新操作") def get_title(self): value = self.driver.title logging.info("获取网页的标题为:%s" % value) return value def quit_browser(self): self.driver.quit() logging.info("关闭浏览器")

    2.2 file_path.py 路径文件

    # —— coding :utf-8 —— # @time: 2020/10/7 20:58 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: file_path.py import os # base_path = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0] 二选1 base_path = os.path.split(os.path.split(os.path.abspath(__file__))[0])[0] # 测试数据路径 TestDatas_path = os.path.join(base_path, 'TestDatas') # 测试用例路径 TestCases_path = os.path.join(base_path, 'TestCases') # 报告路径 reports_path = os.path.join(base_path, r'Outputs\reports') allure_reports_path = os.path.join(base_path,r'Outputs\allure_reports') # 截图路径 screenshots_path = os.path.join(base_path, r'Outputs\screenshots') # 日志路径 logs_path = os.path.join(base_path, r'Outputs\logs') # config_dir = os.path.join(base_path,'Config') if __name__ == '__main__': print(logs_path)

    2.3 my_log.py 自定义日志配置文件

    import logging from logging.handlers import RotatingFileHandler import time from Common import file_dir fmt = " %(asctime)s %(levelname)s %(filename)s %(funcName)s [ line:%(lineno)d ] %(message)s" datefmt = '%a, %d %b %Y %H:%M:%S' handler_1 = logging.StreamHandler() curTime = time.strftime("%Y-%m-%d %H%M", time.localtime()) handler_2 = RotatingFileHandler(file_dir.logs_path + "/Web_Autotest_{0}.log".format(curTime), backupCount=20, encoding='utf-8') #设置rootlogger 的输出内容形式,输出渠道 logging.basicConfig(format=fmt,datefmt=datefmt,level=logging.INFO,handlers=[handler_1,handler_2])

    2.4 send_email.py 发送邮件文件

    # —— coding :utf-8 —— # @time: 2020/10/7 20:59 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: send_email.py """ 使用一个邮箱向另一个邮箱发送测试报告的html文件,这里需要对发送邮件的邮箱进行设置,获取邮箱授权码。 username=“发送邮件的邮箱”, password=“邮箱授权码” 这里要特别注意password不是邮箱密码而是邮箱授权码。 mail_server = "发送邮箱的服务器地址" 这里常用的有 qq邮箱——"stmp.qq.com", 163邮箱——"stmp.163.com" 其他邮箱服务器地址可自行百度 """ import os import smtplib from email.mime.text import MIMEText from email.header import Header import time # 自动发送邮件 class SendEmail(): def send_email(self, new_report): # 读取测试报告中的内容作为邮件的内容 with open(new_report, 'r', encoding='utf8') as f: mail_body = f.read() # 发件人地址 send_addr = 'xxxxxx@qq.com' # 收件人地址 reciver_addr = 'xxxxx@163.com' # 发送邮箱的服务器地址 qq邮箱是'smtp.qq.com', 163邮箱是'smtp.163.com' mail_server = 'smtp.qq.com' now = time.strftime("%Y-%m-%d %H:%M:%S") # 邮件标题 subject = '接口自动化测试报告' + now # 发件人的邮箱及邮箱授权码 username = 'xxxxx@qq.com' password = 'moasmyxgojcgbbch' # 注意这里是邮箱的授权码而不是邮箱密码 # 邮箱的内容和标题 message = MIMEText(mail_body, 'html', 'utf8') # MIMEText(邮箱主体内容,内容类型,字符集) message['Subject'] = Header(subject, charset='utf8') # 发送邮件,使用的使smtp协议 smtp = smtplib.SMTP() smtp.connect(mail_server) smtp.login(username, password) smtp.sendmail(send_addr, reciver_addr.split(','), message.as_string()) smtp.quit() # 获取最新的测试报告地址 def acquire_report_address(self, reports_address): # 测试报告文件夹中的所有文件加入到列表 test_reports_list = os.listdir(reports_address) # 按照升序排序生成新的列表 new_test_reports_list = sorted(test_reports_list) # 获取最新的测试报告 the_last_report = new_test_reports_list[-1] # 最新的测试报告地址 the_last_report_address = os.path.join(reports_address, the_last_report) return the_last_report_address if __name__ == '__main__': # 测试报告存放位置 test_reports_address = '../test_result/html_report' # 查找最新生成的测试报告地址 new_report_addr = SendEmail().acquire_report_address(test_reports_address) # 自动发送邮件 SendEmail().send_email(new_report_addr)

    3. 输出层

    此前已经解析,不再重复

    4. 页面元素定位层

    4.1 indexpage_locators.py 首页元素定位文件

    from selenium.webdriver.common.by import By # 用户名 user_link = (By.XPATH,'//a[@href="/Member/index.html"]') # 投标按钮 bid_button = (By.XPATH,'//*[text()="抢投标"]') #//a[@class="btn btn-special"]

    4.2 investpage_locators.py 投资页面元素定位文件

    # —— coding :utf-8 —— # @time: 2020/10/7 20:59 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: investpage_locators.py from selenium.webdriver.common.by import By # 投资输入框 money_input = (By.XPATH,'//input[contains(@class,"invest-unit-investinput")]') #投标点击按钮 invest_button = (By.XPATH,'//div[@class="body"]//button') # 投资成功弹窗的查看并激活按钮 active_button_on_success_pop = (By.XPATH,'//div[@class="layui-layer-content"]//button') # 投标按钮上的错误信息 errorMsg_from_investButton = (By.XPATH,'//div[@class="layui-layer-content"]') # 页面中间的错误提示信息 errorMsg_from_pageCenter = (By.XPATH,'//div/button[@class="btn btn-special height_style"]/text()')

    4.3 loginpage_locators.py 登录页元素定位文件

    4.4 其他页面元素定位根据需求自行创建封装

    5. 页面对象层(操作方法)

    5.1 index_page.py

    # —— coding :utf-8 —— # @time: 2020/10/7 21:00 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: index_page.py import random from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from PageLocators import indexpage_locators as loc class IndexPage: def __init__(self,driver): self.driver = driver def isExist_logout_ele(self): # 等待5s,元素没有出现 //a[@href="/Index/logout.html"] # 如果存在返回True,如果不存在,返回False try: WebDriverWait(self.driver, 5).until(EC.visibility_of_element_located((By.XPATH, '//a[@href="/Index/logout.html"]'))) return True except: return False # 选标操作 --默认选第一个 = 元素定位的时候,过滤掉不可以投的标 def click_first_bid(self): WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc.bid_button)) self.driver.find_element(*loc.bid_button).click() # 随机选一个标 //*[text()="抢投标"] def click_bid_by_random(self): # 找到所有符合的标 WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(loc.bid_button)) eles = self.driver.find_elements(*loc.bid_button) # 随机数 index = random.randint(0,len(eles)-1) eles[index].click()

    5.2 login_page.py

    # —— coding :utf-8 —— # @time: 2020/10/7 21:01 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: login_page.py from PageLocators.loginpage_locators import LoginPageLocator as loc from Common.base_page import BasePage class LoginPage(BasePage): '''登录页面类''' # 登录操作 def login(self, username, password, remember_user=True): # 输入用户名 # 输入密码 # 点击登录 doc = "登录页面_登录功能" self.wait_eleVisible(loc.user_input,doc=doc) self.input_text(loc.user_input,username,doc) self.input_text(loc.pwd_input,password,doc) # 判断remember_user的值,决定是否勾选 self.click_element(loc.login_but,doc) # 获取错误提示信息 ----登录区域 def get_errorMsg_from_loginArea(self): doc = "登录页面_获取登录区域错误提示信息" self.wait_eleVisible(loc.get_errorMsg_from_login,doc=doc) return self.get_element_text(loc.get_errorMsg_from_login,doc) # 获取错误提示信息---中间区域 def get_login_wrongPwd_noRegArea(self): doc = "登录页面_获取中间区域错误提示信息" self.wait_eleVisible(loc.get_login_wrongPwd_noReg,poll_frequency=0.2,doc=doc) # 错误的密码和没有注册提示信息在中间区域显示 return self.get_element_text(loc.get_login_wrongPwd_noReg,doc)

    5.3 其他页面元素对象操作方法根据需求自行创建函数封装

    6. 测试用例层

    6.1 conftest.py前后置操作文件,如打开浏览器、关闭浏览器、浏览器最大化、刷新页面等

    # —— coding :utf-8 —— # @time: 2020/10/7 21:01 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxxx@qq.com # @File: conftest.py from selenium import webdriver from TestDatas import Common_datas as CD from PageObjects.login_page import LoginPage import pytest driver = None # 声明是一个fixture @pytest.fixture(scope="class") def access_web(): global driver # 前置操作 print("所有用例执行之前,setup整个测试类执行一次") driver = webdriver.Chrome() driver.get(CD.web_login_url) lg = LoginPage(driver) yield (driver, lg) # 分割线:返回值 # 后置操作 print("所有用例执行完成,tearDown整个测试类执行一次") driver.quit() @pytest.fixture def refresh_page(): global driver driver = webdriver.Chrome() # 前置操作 yield # 后置操作 driver.refresh()

    6.2 test_login.py

    # —— coding :utf-8 —— # @time: 2020/10/7 21:02 # @IDE: webTest_frmewok_v2.0 # @Author: jsonLiu # @Email: xxxxxx@qq.com # @File: test_login.py import unittest from selenium import webdriver from PageObjects.login_page import LoginPage from PageObjects.index_page import IndexPage import ddt from TestDatas import Common_datas as CD from TestDatas import login_datas as LD import pytest @pytest.mark.usefixtures("access_web") @pytest.mark.usefixtures("refresh_page") class TestLogin(): # TestCase中不能写__init__ # @classmethod # def setUpClass(cls): # #通过excel读取本功能当中需要的所有测试数 # cls.driver = webdriver.Chrome() # cls.driver.maximize_window() # cls.driver.get(CD.web_login_url) # cls.lg = LoginPage(cls.driver) # # @classmethod # def tearDownClass(cls): # cls.driver.quit() # # def setUp(self): # # pass # def tearDown(self): # '''后置''' # # 正常用例 -登录成功 # self.driver.refresh() # 异常用例 - 错误的手机号格式(大于11位、小于11位、为空、不在号码段) ddt @pytest.mark.parametrize("data", LD.phone_data) # 参数化,把LD.phone_data的测试数据交给自定义参数名为data的参数 def test_login_0_user_wrongFormat(self, data, access_web): # 步骤 输入用户名:xxx,密码:xxx,点击登录 access_web[1].login(data["user"], data["password"]) # 断言 登录页面 提示:请输入正确手机号 # 对别文件内容与期望值是否相等 assert (access_web[0].get_errorMsg_from_loginArea(), data["check"]) # 手机号没有注册 @pytest.mark.parametrize("caseData", LD.wrongPwd_noReg_data) def test_login_1_wrongPwd_noReg(self, caseData,access_web ): # 步骤:输入用户名:xxx, 密码:xxx 点击登录 access_web["user"].login(caseData["user"],caseData["password"]) # 断言: 登录页面 页面中间提示:此账号没有经过授权,请联系管理员! / 密码错误 # 登录页面中, --获取提示框文本内容 # 对比文本内容与期望值是否相等 assert (access_web[0].get_errorMsg_from_loginArea(), caseData["check"]) # fixture的函数名称用来接收它的返回值 @pytest.mark.smoke def test_login_2_normal(self, access_web): # 步骤 输入用户名:xxx,密码:xxx,点击登录 access_web[1].login(LD.success_data["user"], LD.success_data["password"]) # 断言 首页当中能找到“我的帐户”或“退出"关键字 assert IndexPage(access_web[0]).isExist_logout_ele() if __name__ == '__main__': pass

    7. 测试数据层

    7.1 Common_datas.py

    # 全局 --系统访问地址 --登录链接 web_login_url = "http://path_url/Index/login.html" web_invest_url = "http://path_url/loan/loan_detail/Id/25750.html"

    7.2 login_datas.py

    # 正常用例 -登录成功 success_data = {"user":"13457681358","password":"123456"} # 异常用例 - 错误的手机号格式(大于11位、小于11位、为空、不在号码段) phone_data = [ {"user":"1345768135","password":"123456","check":"请输入正确的手机号"}, # 小于11位 {"user":"134576813588","password":"123456","check":"请输入正确的手机号"}, #大于11位 {"user":"","password":"123456","check":"请输入手机号"}, # 手机号为空 {"user":"13457681358","password":"123456","check":"请输入正确的手机号"} # 不在手机号段 ] wrongPwd_noReg_data = [ {"user":"13457681358","password":"12345","check":"帐号或密码错误!"}, # 密码错误 {"user":"13457681357","password":"123456","check":"此账号没有经过授权,请联系管理员!"}, # 账号没有授权 ]

    7.3 其他测试数据文件根据项目需要自行创建

    8. readme.md 帮助文件

    web自动化测试基本框架 -Common -Outputs -PageLocators -PageObjects -TestCases -TestDatas -run.py 常用命令: 创建虚拟环境 mkvirtualenv -p python3 虚拟环境名字 查看虚拟环境 workon 切换虚拟环境 workon 虚拟环境名字` 退出当前虚拟环境 deactivate 删除虚拟环境 rmvirtualenv 虚拟环境名字` 导入requirements.txt工具包命令: pip install -r requirements.txt 导入requirements.txt工具包命令: pip freeze > requirements.txt 安装命令: pip install 包名 移除命令: pip uninstall 包名 查看已安装: pip list

    9. requirements.txt 项目依赖工具包

    atomicwrites==1.4.0 attrs==20.2.0 colorama==0.4.3 ddt==1.4.1 iniconfig==1.0.1 more-itertools==8.5.0 packaging==20.4 pluggy==0.13.1 py==1.9.0 pyparsing==2.4.7 pytest==6.0.2 pytest-html==2.1.1 pytest-metadata==1.10.0 pytest-rerunfailures==9.1 pywin32==228 selenium==3.141.0 six==1.15.0 toml==0.10.1 urllib3==1.25.10

    10.run.py 项目运行文件

    import HTMLTestRunner from Common.file_path import * import unittest # 实例化套件对象 s = unittest.TestSuite() # 1.实例化TestLoader对象 # 2. 使用discover找到一个目录下所有测试用例 # 使用s loader = unittest.TestLoader() s.addTests(loader.discover(testcases_dir)) # # 运行 # runner = unittest.TextTestRunner() # runner.run() fp = open(htmlreport_dir+'/autoTest_report.html','wb') runner = HTMLTestRunner.HTMLTestRunner( stream=fp, title="单元测试报告", description="单元测试报告" ) runner.run(s)

    四、与Jenkins集成

    关于allure报告与Jenkins集成

    windows版可参考此篇 https://blog.csdn.net/weixin_43723664/article/details/105489504linux版可参考此篇: https://www.cnblogs.com/wang-mengmeng/p/11784805.html
    Processed: 0.019, SQL: 8