python+selenium自动化框架搭建的方法步骤
环境及使用软件信息
- python 3
- selenium 3.13.0
- xlrd 1.1.0
- chromedriver
- HTMLTestRunner
说明:
selenium/xlrd只需要再python环境下使用pip install 名称即可进行对应的安装。 安装完成后可使用pip list查看自己的安装列表信息。
chromedriver:版本需和自己的chrome浏览器对应,百度下载。 作用:对chrome浏览器进行驱动。
HTMLTestRunner:HTMLTestRunner是Python标准库的unittest模块的一个扩展。它生成易于使用的HTML测试报告。 下载后放在对应的包中,使用import引入即可使用。
项目结构
项目主要包括以下几个部分
config#存放配置文件
- config.ini
- globalparameter.py#全局变量的py文件
log #存放项目日志
- mylog.log
data #存放测试数据
- test.xls #测试数据存放
driver #存放项目使用到的驱动
- chromedriver.exe #chrome浏览器驱动文件
report #存放生成的测试报告
src #存放源代码
- common #共同的文件
- HTMLTestRunner.py #用于生成HTML格式的测试报告
- browser_engine.py#打开关闭浏览器
- excle_data#封装xlrd的excel数据的读取
- base_page.py #对浏览器的操作
- log.py#日志
- db_connect#链接数据库
- send_email#发送邮件
- pageobject#存放页面元素,页面操作
- testcase#存放用例
runtest.py#代码启动入口
代码实现
config包configini
# this is config file, only store browser type and server URL [browserType] #browserName = Firefox browserName = Chrome #browserName = IE [testServer] URL = [smtp_sever]#邮箱服务器注意:应填写邮箱@之后的地址,例如qq邮箱就写smtp.qq.com smtp_sever =smtp.qq.com [email_name] email_name = [email_password] email_password = [email_to] email_to = [dbServer] dbServer= [port] port=3306 [user] user=root [password] password= [db] db=
config包glbalparameter-全局变量
# coding:utf-8 import time,os ''' 配置全局参数 ''' project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # project_path1=os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)[0]),'.')) # print (project_path) # print (project_path1) #配置文件存放路径 # config_file_path = project_path + '/config/config.ini' config_file_path = project_path + '\\config\\config.ini' #浏览器驱动存放路径 chrome_driver_path = project_path + '\\driver\\chromedriver.exe' ie_driver_path = project_path + '\\driver\\IEDriverServer.exe' #execl测试数据文档存放路径 test_data_path=project_path+"\\data\\testData.xlsx" #日志文件存储路径 log_path=project_path+"\\log\\mylog.log" print ("日志路径:"+log_path) # 测试报告存储路径,并以当前时间作为报告名称前缀 report_path = project_path+"\\report\\" report_name = report_path+time.strftime('%Y%m%d%H%S', time.localtime()) # 异常截图存储路径,并以当前时间作为图片名称前缀 img_path = project_path+"\\error_img\\"+time.strftime('%Y%m%d%H%S', time.localtime()) #测试用例代码存放路径(用于构建suite,注意该文件夹下的文件都应该以test开头命名) test_case_path=project_path+"\\src\\testcase" #login_username="-------------" #login_password="-------------" # if __name__=='__main__': # test1 = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)[0]), '.'))
src包(源代码)-common(共同使用的)
其中,src需要进行初始化,否则,在其他模块进行引用时无法找到。在python中定义包的方法是在对应的文件夹下创建一个__init__.py的文件即可。
readexcel.py(网上简单的)
读取excel数据文件
import xlrd # 读取excel文件中对应row和cel数据信息5 def readExcel(path,row,cel): workBook = xlrd.open_workbook(path) sheet = workBook.sheet_by_name("Sheet1") value = sheet.cell(row,cel).value return value
excel_data.py(我的)
#封装xlrd的excel数据的读取 # coding:utf-8 from src.common import log from config.globalparameter import test_data_path import xlrd ''' 读取excel文件 ''' class excel: def __init__(self): self.mylog = log.log() def open_excel(self,file): u'''读取excel文件''' try: data = xlrd.open_workbook(file) return data except Exception as e: self.mylog.error(u"打开excel文件失败") def excel_table(self,file, sheetName): u'''装载list''' data = self.open_excel(file) # 通过工作表名称,获取到一个工作表 table = data.sheet_by_name(sheetName) # 获取行数 Trows = table.nrows # 获取 第一行数据 Tcolnames = table.row_values(0) lister = [] for rownumber in range(1,Trows): row = table.row_values(rownumber) if row: app = {} for i in range(len(Tcolnames)): app[Tcolnames[i]] = row[i] lister.append(app) return lister def get_list(self,sheetname): try: data_list = self.excel_table(test_data_path, sheetname) assert len(data_list)>=0,u'excel标签页:'+sheetname+u'为空' return data_list except Exception as e: self.mylog.error(u'excel标签页:'+sheetname+u'为空') raise e
base_page.py
#对浏览器的操作 # coding:utf-8 import time from src.common.log import log from selenium.webdriver.support.select import Select from config.globalparameter import project_path,img_path from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium import webdriver from time import sleep import re class BasePage(object): """" 定义一个页面基类,让所有页面都继承这个类,封装一些常用的页面操作方法到这个类 """ def __init__(self,driver): self.driver=driver self.mylog=log() # quit browser and end testing def quit_browse(self): self.driver.quit() # 浏览器前进操作 def forward(self): self.driver.forward() self.mylog.info("Click forward on current page.") # 浏览器后退操作 def back(self): self.driver.back() self.mylog.info("Click back on current page.") # 隐式等待 def wait(self, seconds): self.driver.implicitly_wait(seconds) self.mylog.info("wait for %d seconds." % seconds) # 点击关闭当前窗口 def close(self): try: self.driver.close() self.mylog.info("Closing and quit the browser.") except NameError as e: self.mylog.error("Failed to quit the browser with %s" % e) # 截图,保存图片 def img_screenshot(self, img_name): try: self.driver.get_screenshot_as_file(img_path + img_name + '.png') except: self.mylog.error(u'截图失败:' + img_name) # 切换到新窗口 def Current_handel(self): all_handles=self.driver.window_handles for handle in all_handles: self.driver.switch_to.window(handle) # 重写find_element方法,增加定位元素的健壮性 def find_element(self, *selector): try: # 确保元素是可见的。 # 注意:以下入参为元组的元素,需要加*。Python存在这种特性,就是将入参放在元组里。 WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(selector)) print("self.driver.find_element(*selector)",self.driver.find_element(*selector)) return self.driver.find_element(*selector) except: self.mylog.error(u'找不到元素:'+str(selector)) #输入,重新send_keys,,先清除后输入 def type(self,selector,text): try: # selector = getattr(self, "_%s" % selector) el=self.find_element(*selector) el.clear() el.send_keys(text) except NameError as e: self.mylog.error("Failed to type in input box with %s" % e) def click(self,selector): try: el=self.find_element(*selector) el.click() sleep(3) except NameError as e: self.mylog.error("Failed to click the element with %s" % e) # 通过value获取下拉菜单元素并点击 def select_element_text(self,selector,text): try: el=self.find_element(*selector) Select(el).select_by_visible_text(text) except: self.mylog.error(u'找不到元素:'+str(selector)) # 通过index获取下拉菜单元素并点击 def select_element_index(self,selector,index): try: el=self.find_element(*selector) Select(el).select_by_index(index) except: self.mylog.error(u'找不到元素:' + str(selector)) #获取元素的属性值 def get_Attribute(self,selector,value): el = self.driver.find_element(selector).get_attribute(value) return el # 获取元素的文本的值 def get_text(self,selector): el=self.find_element(*selector).text return el # 校验按钮是否为选中状态 def is_selected(self,selector): el=self.find_element(*selector) if el.is_selected(): print(el+"被选中") else: print("请重新选中") # 获取网页标题 def get_page_title(self): # logger.info("Current page title is %s" % self.driver.title) return self.driver.title # 获取单个表单元素 def click_table_element(self, selector, text1, index, p_index, a_index): el = self.find_element(*selector) table_tr_list = el.find_elements_by_tag_name("tr") flag = 0 breakflag = False # 循环table中tr的值 for tr in table_tr_list: # 切换tr中的text再循环 for i in (tr.text).split(" "): # 如果i的值=testStop中传入的值 # print("111111") # print("i的值", i) if breakflag: break if i == text1: # 去查找当前值的td所在的位置 ul = table_tr_list[flag].find_elements_by_tag_name("td")[index] # 查找td下p的元素 ee = ul.find_elements_by_tag_name("p") if len(ee) == 0: # 邱菊华新增这一行,兼容电桩类型页面的元素 tt = ul.find_elements_by_tag_name("div") # 循环td下的p元素 n = 0 for j in ee or tt: if breakflag: break # 查看p下面的a元素 n = n + 1 if n == p_index: tt = j.find_elements_by_tag_name("a") flagss = 0 # 循环a元素,循环一次后flagss+1, for o in tt: flagss = flagss + 1 # 如flagss==2,即第二个a元素 if flagss == a_index: # 点击o元素,即删除按钮 time.sleep(1) # o.click() return o breakflag = True break flag = flag + 1 def cc(self, selector, text): el = self.find_element(selector) try: el.send_keys(text) except NameError as e: self.mylog.error("Failed to type in input box with %s" % e) # 重写find_elements方法,增加定位元素的健壮性 def find_elements(self, *selector): try: # 确保元素是可见的。 # 注意:以下入参为元组的元素,需要加*。Python存在这种特性,就是将入参放在元组里。 WebDriverWait(self.driver, 10).until(EC.visibility_of_element_located(selector)) return self.driver.find_elements(*selector) except: self.mylog.error(u'找不到元素:' + str(selector)) # 批量操作 针对表格 可以传入多个参数(这里采用可变参数来进行判断) def table_element(self, selector, *text): # 先获取页面元素,这里是table print("selector的值",selector) el = self.find_element(*selector) # 查看table下的tr table_tr_list = el.find_elements_by_tag_name("tr") flag = 0 flags = [] breakflag = False # 循环table中所有的tr for tr in table_tr_list: # 循环一个tr,flag+1 if breakflag: break flag = flag + 1 # 循环每一行并切割取值 for i in tr.text.split(" "): if breakflag: break try: # 如果i 在text里面 if len(text)==0: print("请输入要删除的值") elif len(text)==1: value="".join(tuple(text)) if i==value: flags.append(flag) breakflag = True break else: if i in text: # print(flag) # 把当前的flag即行数传到flags中 flags.append(flag) except Exception as e: print("未找到相应的结果") # 返回flags 供后面的函数调用 return flags def ul_li(self,selector): el=self.find_element(*selector) return el.find_elements_by_xpath('li') def getdigital(self,oristring): return re.sub("\D", "",oristring) #批量传入元素类型(1:文本框输入 2:下拉框选择 3:时间控件)、元素、值 def add(self,elements): pass for i in elements: if i[0]==1: self.type(i[1], i[2]) if i[0]==2: self.select_element_index(i[1],i[2]) def clear(self,selector): el = self.find_element(*selector) el.clear() def get_value(self,selector): """获取元素的value属性""" return self.driver.find_element(*selector).get_attribute("value")
browser_engine.py
打开关闭浏览器方法的封装
# -*- coding:utf-8 -*- import configparser import os.path from selenium import webdriver from config.globalparameter import img_path,chrome_driver_path,ie_driver_path,project_path,config_file_path class BrowserEngine(object): def __init__(self, driver): self.driver = driver # read the browser type from config.ini file, return the driver def open_browser(self, driver): config = configparser.ConfigParser() config.read(config_file_path,encoding='UTF-8') #config.read(config_file_path)#这是原来的 browser = config.get("browserType", "browserName") # logger.info("You had select %s browser." % browser) url = config.get("testServer", "URL") if browser == "Firefox": driver = webdriver.Firefox() # logger.info("Starting firefox browser.") elif browser == "Chrome": driver = webdriver.Chrome(chrome_driver_path) # logger.info("Starting Chrome browser.") elif browser == "IE": driver = webdriver.Ie(ie_driver_path) # logger.info("Starting IE browser.") driver.get(url) driver.maximize_window() driver.implicitly_wait(10) return driver def quit_browser(self): # logger.info("Now, Close and quit the browser.") self.driver.quit()
db_connect.py数据库链接
# coding:utf-8 import psycopg2 import configparser from config.globalparameter import config_file_path class Db_Connect(object): def __init__(self): config=configparser.ConfigParser() config.read(config_file_path) self.host=config.get("dbServer","dbServer") self.user=config.get("user","user") self.password=config.get("password","password") self.db=config.get("db","db") self.port=config.get("port","port") def db_connect(self): db=psycopg2.connect(host=self.host,user=self.user,password=self.password,db=self.db,port=int(self.port)) return db def db_executesql(self,sql): db=psycopg2.connect(host=self.host,user=self.user,password=self.password,db=self.db,port=int(self.port)) cur=db.cursor() try: cur.execute(sql) return cur except Exception as e: raise e
HTMLTesstRunner.py(测试报告)代码过长可到网上找
send_email.py(邮件发送测试报告)
# coding:utf-8 __author__ = 'helen' import os,smtplib,os.path from config import globalparameter as gl from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from src.common import log import configparser ''' 邮件发送最新的测试报告 ''' class send_email: def __init__(self): self.mylog = log.log() # 定义邮件内容 def email_init(self,report,reportName): with open(report,'rb')as f: mail_body = f.read() config=configparser.ConfigParser() config.read(gl.config_file_path,encoding='UTF-8') smtp_sever=config.get("smtp_sever","smtp_sever") email_password=config.get("email_password","email_password") email_name=config.get("email_name","email_name") email_to=config.get("email_to","email_to") # 创建一个带附件的邮件实例 msg = MIMEMultipart() # 以测试报告作为邮件正文 msg.attach(MIMEText(mail_body,'html','utf-8')) report_file = MIMEText(mail_body,'html','utf-8') # 定义附件名称(附件的名称可以随便定义,你写的是什么邮件里面显示的就是什么) report_file["Content-Disposition"] = 'attachment;filename='+reportName msg.attach(report_file) # 添加附件 msg['Subject'] = '自动化测试报告:'+reportName # 邮件标题 msg['From'] = email_name #发件人 msg['To'] = email_to #收件人列表 try: server = smtplib.SMTP(smtp_sever) server.login(email_name,email_password) server.sendmail(msg['From'],msg['To'].split(';'),msg.as_string()) server.quit() except smtplib.SMTPException: self.mylog.error(u'邮件发送测试报告失败 at'+__file__) def sendReport(self): # 找到最新的测试报告 report_list = os.listdir(gl.report_path) report_list.sort(key=lambda fn: os.path.getmtime(gl.report_path+fn) if not os.path.isdir(gl.report_path+fn) else 0) new_report = os.path.join(gl.report_path,report_list[-1]) # 发送邮件 self.email_init(new_report,report_list[-1])
log.py(日志)
# coding:utf-8 import logging from config import globalparameter as gl ''' 配置日志文件,输出INFO级别以上的日志 ''' class log: def __init__(self): self.logname = "mylog" def setMSG(self, level, msg): logger = logging.getLogger() # 定义Handler输出到文件和控制台 fh = logging.FileHandler(gl.log_path) ch = logging.StreamHandler() # 定义日志输出格式 formater = logging.Formatter("%(asctime)s %(levelname)s %(message)s' ") fh.setFormatter(formater) ch.setFormatter(formater) # 添加Handler logger.addHandler(fh) logger.addHandler(ch) # 添加日志信息,输出INFO级别的信息 logger.setLevel(logging.INFO) if level=='debug': logger.debug(msg) elif level=='info': logger.info(msg) elif level=='warning': logger.warning(msg) elif level=='error': logger.error(msg) # 移除句柄,否则日志会重复输出 logger.removeHandler(fh) logger.removeHandler(ch) fh.close() def debug(self, msg): self.setMSG('debug', msg) def info(self, msg): self.setMSG('info', msg) def warning(self, msg): self.setMSG('warning', msg) def error(self, msg): self.setMSG('error', msg)
testcase演示test_search.py
# coding:utf-8 import unittest from src.common.browser_engine import BrowserEngine from selenium.webdriver.common.keys import Keys from selenium import webdriver from src.pageobject.searchpage.searchpage import SearchPage import time class Search(unittest.TestCase): @classmethod def setUpClass(cls): browser=BrowserEngine(cls) cls.driver=browser.open_browser(cls) cls.driver.implicitly_wait(3) cls.searchpage=SearchPage(cls.driver) cls.searchpage.goto_searchpage() @classmethod def tearDownClass(cls): cls.driver.quit() def test01_searchoname(self): #webdriver.ActionChains(self.driver).send_keys(Keys.ENTER).perform() print('代码执行完成') time.sleep(3)
测试用例中的相关说明:
- setup():每个测试函数运行前运行
- teardown():每个测试函数运行完后执行
- setUpClass():必须使用@classmethod 装饰器,所有test运行前运行一次
- tearDownClass():必须使用@classmethod装饰器,所有test运行完后运行一次
测试用例执行runtest.py
使用HTMLTestRunner执行测试用例,并生成测试报告。
# conding :utf-8 import unittest import time from config.globalparameter import test_case_path,report_name from src.common import send_email from src.common import HTMLTestRunner """构建测试套件,并执行测试""" #构建测试集,包含src/testsuite目录下的所有以test开头的.py文件 print (test_case_path) suite = unittest.defaultTestLoader.discover(start_dir=test_case_path,pattern='test*.py') if __name__=='__main__': report=report_name+"Report.html" fb=open(report,'wb') runner=HTMLTestRunner.HTMLTestRunner(stream=fb,title=u'陕西项目自动化测试报告',description=u'测试Team') runner.run(suite) fb.close() email=send_email.send_email() email.sendReport()
到此这篇关于python+selenium自动化框架搭建的方法步骤的文章就介绍到这了,更多相关python selenium自动化搭建内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!